summaryrefslogtreecommitdiff
path: root/src/clarktown
diff options
context:
space:
mode:
authorAsko Nõmm <asko@bien.ee>2022-04-19 17:50:19 +0300
committerAsko Nõmm <asko@bien.ee>2022-04-19 17:50:19 +0300
commit52203a49aa544b2c11c96445d8732893160c436b (patch)
tree84d7b0e9af92770647643bdf7ddbb898663bd7b8 /src/clarktown
parent059bfa7bd9bfdde0c75646bf1dfc20d23da8a02c (diff)
WIP #16
Pretty much done. Needs more testing. And new documentation.
Diffstat (limited to 'src/clarktown')
-rw-r--r--src/clarktown/core.clj151
-rw-r--r--src/clarktown/correctors.clj17
-rw-r--r--src/clarktown/correctors/atx_heading_block.clj19
-rw-r--r--src/clarktown/correctors/code_block.clj27
-rw-r--r--src/clarktown/matchers/code_block.clj10
-rw-r--r--src/clarktown/matchers/empty_block.clj (renamed from src/clarktown/parsers/empty_block.clj)12
-rw-r--r--src/clarktown/matchers/heading_block.clj29
-rw-r--r--src/clarktown/matchers/horizontal_line_block.clj10
-rw-r--r--src/clarktown/matchers/list_block.clj10
-rw-r--r--src/clarktown/matchers/quote_block.clj11
-rw-r--r--src/clarktown/parser.clj195
-rw-r--r--src/clarktown/parsers.clj136
-rw-r--r--src/clarktown/parsers/horizontal_line_block.clj16
-rw-r--r--src/clarktown/renderers/bold.clj (renamed from src/clarktown/parsers/bold.clj)2
-rw-r--r--src/clarktown/renderers/code_block.clj (renamed from src/clarktown/parsers/code_block.clj)9
-rw-r--r--src/clarktown/renderers/empty_block.clj7
-rw-r--r--src/clarktown/renderers/heading_block.clj (renamed from src/clarktown/parsers/heading_block.clj)40
-rw-r--r--src/clarktown/renderers/horizontal_line_block.clj7
-rw-r--r--src/clarktown/renderers/inline_code.clj (renamed from src/clarktown/parsers/inline_code.clj)2
-rw-r--r--src/clarktown/renderers/italic.clj (renamed from src/clarktown/parsers/italic.clj)2
-rw-r--r--src/clarktown/renderers/link_and_image.clj (renamed from src/clarktown/parsers/link_and_image.clj)2
-rw-r--r--src/clarktown/renderers/list_block.clj (renamed from src/clarktown/parsers/list_block.clj)10
-rw-r--r--src/clarktown/renderers/paragraph_block.clj (renamed from src/clarktown/parsers/paragraph_block.clj)2
-rw-r--r--src/clarktown/renderers/quote_block.clj (renamed from src/clarktown/parsers/quote_block.clj)10
-rw-r--r--src/clarktown/renderers/strikethrough.clj (renamed from src/clarktown/parsers/strikethrough.clj)2
25 files changed, 403 insertions, 335 deletions
diff --git a/src/clarktown/core.clj b/src/clarktown/core.clj
index a6ed42c..cabd6e6 100644
--- a/src/clarktown/core.clj
+++ b/src/clarktown/core.clj
@@ -1,7 +1,145 @@
(ns clarktown.core
(:require
- [clarktown.parser :as parser]
- [clarktown.parsers :as parsers]))
+ [clojure.string :as string]
+ [clarktown.parsers :as parsers]
+ [clarktown.correctors :as correctors]))
+
+
+(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- correct-block-separations
+ "Corrects block separations and adds newlines above or
+ below a block where needed."
+ [correctors lines]
+ (->> lines
+ (map-indexed
+ (fn [index line]
+ (let [add-line-above? (some #(true? (% lines line index)) (:empty-line-above? correctors))
+ add-line-below? (some #(true? (% lines line index)) (:empty-line-below? correctors))]
+ (cond
+ ; If code block starts but there is no empty newline
+ ; above, let's fix that
+ (and add-line-above?
+ (not add-line-below?))
+ (str \newline line)
+
+ ; If the code block ends, but there is no empty newline
+ ; below, let's fix that.
+ (and add-line-below?
+ (not add-line-above?))
+ (str line \newline)
+
+ ; If the code block needs a newline both above and below,
+ ; let's fix that.
+ (and add-line-above?
+ add-line-below?)
+ (str \newline line \newline)
+
+ ; otherwise is what it is
+ :else line))))))
+
+
+(defn- correct-markdown
+ "Corrects invalid Markdown for the parser."
+ [markdown given-correctors]
+ (let [lines (string/split-lines markdown)]
+ (->> lines
+ (correct-block-separations (:block-separations given-correctors))
+ (string/join \newline))))
+
+
+(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
+ (recur (loop [block block
+ renderers (:renderers (first parsers))]
+ (if (empty? renderers)
+ block
+ (let [renderer (first renderers)]
+ (recur (renderer block parsers)
+ (drop 1 renderers)))))
+ (drop 1 parsers)))))
+
+
+(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)]
+ (->> (string/trim block)
+ (parse-block-with-known-parser parser parsers))
+ (->> (string/trim block)
+ (parse-block-with-unknown-parsers parsers)))))
+
+
+(defn parse
+ "Parses given `markdown` with `parsers`."
+ [markdown given-parsers given-correctors]
+ (let [blocks (-> (correct-markdown markdown given-correctors)
+ (string/split #"\n\n")
+ stitch-code-blocks)
+ parsed-blocks (parse-blocks blocks given-parsers)]
+ (string/join "\n\n" parsed-blocks)))
(defn render
@@ -22,9 +160,8 @@
:renderers [(fn [block] ...) (fn [block] ...)]}
```"
([markdown]
- (render markdown parsers/parsers))
+ (render markdown parsers/default-parsers))
([markdown given-parsers]
- (parser/parse markdown given-parsers)))
-
-(comment
- (render (slurp "./test.md"))) \ No newline at end of file
+ (render markdown given-parsers correctors/default-correctors))
+ ([markdown given-parsers given-correctors]
+ (parse markdown given-parsers given-correctors))) \ No newline at end of file
diff --git a/src/clarktown/correctors.clj b/src/clarktown/correctors.clj
new file mode 100644
index 0000000..ba49879
--- /dev/null
+++ b/src/clarktown/correctors.clj
@@ -0,0 +1,17 @@
+(ns clarktown.correctors
+ (:require
+ [clarktown.correctors.code-block :as code-block]
+ [clarktown.correctors.atx-heading-block :as atx-heading-block]))
+
+
+(def block-separation-correctors
+ {:empty-line-above?
+ [code-block/empty-line-above?
+ atx-heading-block/empty-line-above?]
+ :empty-line-below?
+ [code-block/empty-line-below?
+ atx-heading-block/empty-line-below?]})
+
+
+(def default-correctors
+ {:block-separations block-separation-correctors}) \ No newline at end of file
diff --git a/src/clarktown/correctors/atx_heading_block.clj b/src/clarktown/correctors/atx_heading_block.clj
new file mode 100644
index 0000000..a792572
--- /dev/null
+++ b/src/clarktown/correctors/atx_heading_block.clj
@@ -0,0 +1,19 @@
+(ns clarktown.correctors.atx-heading-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn empty-line-above?
+ [lines line index]
+ (and (string/starts-with? (string/trim line) "#")
+ (> index 0)
+ (not (= (-> (nth lines (- index 1))
+ string/trim) ""))))
+
+
+(defn empty-line-below?
+ [lines line index]
+ (and (string/starts-with? (string/trim line) "#")
+ (< index (- (count lines) 1))
+ (not (= (-> (nth lines (+ index 1))
+ string/trim) "")))) \ No newline at end of file
diff --git a/src/clarktown/correctors/code_block.clj b/src/clarktown/correctors/code_block.clj
new file mode 100644
index 0000000..e767390
--- /dev/null
+++ b/src/clarktown/correctors/code_block.clj
@@ -0,0 +1,27 @@
+(ns clarktown.correctors.code-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn empty-line-above?
+ [lines line index]
+ (and (= (string/trim line) "```")
+ (> index 0)
+ (->> (take index lines)
+ (filter #(= (string/trim %) "```"))
+ count
+ odd?)
+ (not (= (-> (nth lines (- index 1))
+ string/trim) ""))))
+
+
+(defn empty-line-below?
+ [lines line index]
+ (and (= (string/trim line) "```")
+ (< index (- (count lines) 1))
+ (->> (take index lines)
+ (filter #(= (string/trim %) "```"))
+ count
+ even?)
+ (not (= (-> (nth lines (+ index 1))
+ string/trim) "")))) \ No newline at end of file
diff --git a/src/clarktown/matchers/code_block.clj b/src/clarktown/matchers/code_block.clj
new file mode 100644
index 0000000..655c951
--- /dev/null
+++ b/src/clarktown/matchers/code_block.clj
@@ -0,0 +1,10 @@
+(ns clarktown.matchers.code-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn match?
+ "Determines whether we're dealing with a code block."
+ [block]
+ (and (string/starts-with? block "```")
+ (string/ends-with? block "```"))) \ No newline at end of file
diff --git a/src/clarktown/parsers/empty_block.clj b/src/clarktown/matchers/empty_block.clj
index 0ed5a08..cc7b7f4 100644
--- a/src/clarktown/parsers/empty_block.clj
+++ b/src/clarktown/matchers/empty_block.clj
@@ -1,17 +1,11 @@
-(ns clarktown.parsers.empty-block
+(ns clarktown.matchers.empty-block
(:require
[clojure.string :as string]))
-(defn is?
+(defn match?
"Determines if the current block is an empty block or not."
[block]
(-> (string/replace block #"\n" "")
string/trim
- string/blank?))
-
-
-(defn render
- "Renders an empty block."
- [_ _]
- "")
+ string/blank?)) \ No newline at end of file
diff --git a/src/clarktown/matchers/heading_block.clj b/src/clarktown/matchers/heading_block.clj
new file mode 100644
index 0000000..2295f26
--- /dev/null
+++ b/src/clarktown/matchers/heading_block.clj
@@ -0,0 +1,29 @@
+(ns clarktown.matchers.heading-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn is-atx-heading?
+ "Determines whether the given block is a atx heading."
+ [block]
+ (-> (string/replace block #"\n" "")
+ string/trim
+ (string/starts-with? "#")))
+
+
+(defn is-settext-heading?
+ "Determines whether the given block is a settext heading."
+ [block]
+ (let [lines (-> (string/split-lines block))
+ chars (-> (last lines)
+ string/trim
+ (string/split #""))]
+ (and (> (count lines) 1)
+ (every? #{"-" "="} chars))))
+
+
+(defn match?
+ "Determines whether the given block is a heading block."
+ [block]
+ (or (is-atx-heading? block)
+ (is-settext-heading? block))) \ No newline at end of file
diff --git a/src/clarktown/matchers/horizontal_line_block.clj b/src/clarktown/matchers/horizontal_line_block.clj
new file mode 100644
index 0000000..a2dde6e
--- /dev/null
+++ b/src/clarktown/matchers/horizontal_line_block.clj
@@ -0,0 +1,10 @@
+(ns clarktown.matchers.horizontal-line-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn match?
+ "Determines whether the given block is a horizontal line block."
+ [block]
+ (or (= "***" (string/trim block))
+ (= "---" (string/trim block)))) \ No newline at end of file
diff --git a/src/clarktown/matchers/list_block.clj b/src/clarktown/matchers/list_block.clj
new file mode 100644
index 0000000..a37b06e
--- /dev/null
+++ b/src/clarktown/matchers/list_block.clj
@@ -0,0 +1,10 @@
+(ns clarktown.matchers.list-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn match?
+ "Determines whether we're dealing with a list block or not."
+ [block]
+ (->> (string/trim block)
+ (re-matches #"(?s)^(\d\.\s|\*{1}\s|\-{1}\s).*$"))) \ No newline at end of file
diff --git a/src/clarktown/matchers/quote_block.clj b/src/clarktown/matchers/quote_block.clj
new file mode 100644
index 0000000..230b561
--- /dev/null
+++ b/src/clarktown/matchers/quote_block.clj
@@ -0,0 +1,11 @@
+(ns clarktown.matchers.quote-block
+ (:require
+ [clojure.string :as string]))
+
+
+(defn match?
+ "Determines whether the given block is a quote block."
+ [block]
+ (-> (string/replace block #"\n" "")
+ string/trim
+ (string/starts-with? ">"))) \ No newline at end of file
diff --git a/src/clarktown/parser.clj b/src/clarktown/parser.clj
deleted file mode 100644
index ecee37d..0000000
--- a/src/clarktown/parser.clj
+++ /dev/null
@@ -1,195 +0,0 @@
-(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- needs-empty-line-above?
- "Determines whether the current line needs an empty line correction
- above."
- [lines line index]
- (cond
- ; code block
- (and (= (string/trim line) "```")
- (> index 0)
- (->> (take index lines)
- (filter #(= (string/trim %) "```"))
- count
- odd?)
- (not (= (-> (nth lines (- index 1))
- string/trim) "")))
- true
-
- ; ATX heading block
- (and (string/starts-with? (string/trim line) "#")
- (> index 0)
- (not (= (-> (nth lines (- index 1))
- string/trim) "")))
- true
-
-
- ; everything else stays normal
- :else false))
-
-
-(defn- needs-empty-line-below?
- "Determines whether the current line needs an empty line correction
- below."
- [lines line index]
- (cond
- ; code block
- (and (= (string/trim line) "```")
- (< index (- (count lines) 1))
- (->> (take index lines)
- (filter #(= (string/trim %) "```"))
- count
- even?)
- (not (= (-> (nth lines (+ index 1))
- string/trim) "")))
- true
-
- ; ATX heading block
- (and (string/starts-with? (string/trim line) "#")
- (< index (- (count lines) 1))
- (not (= (-> (nth lines (+ index 1))
- string/trim) "")))
- true
-
- ; everything else stays normal
- :else false))
-
-
-(defn- correct-block-separations
- "Corrects block separations and adds newlines above or
- below a block where needed."
- [lines]
- (->> lines
- (map-indexed
- (fn [index line]
- (let [add-line-above? (needs-empty-line-above? lines line index)
- add-line-below? (needs-empty-line-below? lines line index)]
- (cond
- ; If code block starts but there is no empty newline
- ; above, let's fix that
- (and add-line-above?
- (not add-line-below?))
- (str \newline line)
-
- ; If the code block ends, but there is no empty newline
- ; below, let's fix that.
- (and add-line-below?
- (not add-line-above?))
- (str line \newline)
-
- ; If the code block needs a newline both above and below,
- ; let's fix that.
- (and add-line-above?
- add-line-below?)
- (str \newline line \newline)
-
- ; otherwise is what it is
- :else line))))))
-
-
-(defn- correct-markdown
- "Corrects invalid Markdown for the parser."
- [markdown]
- (let [lines (string/split-lines markdown)]
- (->> lines
- correct-block-separations
- (string/join \newline))))
-
-
-(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
- (recur (loop [block block
- renderers (:renderers (first parsers))]
- (if (empty? renderers)
- block
- (let [renderer (first renderers)]
- (recur (renderer block parsers)
- (drop 1 renderers)))))
- (drop 1 parsers)))))
-
-
-(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)]
- (->> (string/trim block)
- (parse-block-with-known-parser parser parsers))
- (->> (string/trim block)
- (parse-block-with-unknown-parsers parsers)))))
-
-
-(defn parse
- "Parses given `markdown` with `parsers`."
- [markdown parsers]
- (let [blocks (-> (correct-markdown markdown)
- (string/split #"\n\n")
- stitch-code-blocks)
- parsed-blocks (parse-blocks blocks parsers)]
- (string/join "\n\n" parsed-blocks)))
diff --git a/src/clarktown/parsers.clj b/src/clarktown/parsers.clj
index cd909b3..77c9794 100644
--- a/src/clarktown/parsers.clj
+++ b/src/clarktown/parsers.clj
@@ -1,45 +1,95 @@
(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]
- [clarktown.parsers.code-block :as code-block]
- [clarktown.parsers.list-block :as list-block]
- [clarktown.parsers.paragraph-block :as paragraph-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 [link-and-image/render
- bold/render
- italic/render
- inline-code/render
- strikethrough/render
- heading-block/render]}
- {:matcher quote-block/is?
- :renderers [quote-block/render]}
- {:matcher code-block/is?
- :renderers [code-block/render]}
- {:matcher list-block/is?
- :renderers [link-and-image/render
- bold/render
- italic/render
- inline-code/render
- strikethrough/render
- list-block/render]}
- {:renderers [link-and-image/render
- bold/render
- italic/render
- inline-code/render
- strikethrough/render
- paragraph-block/render]}])
+ [clarktown.matchers.empty-block]
+ [clarktown.renderers.empty-block]
+ [clarktown.matchers.horizontal-line-block]
+ [clarktown.renderers.horizontal-line-block]
+ [clarktown.matchers.heading-block]
+ [clarktown.renderers.heading-block]
+ [clarktown.matchers.quote-block]
+ [clarktown.renderers.quote-block]
+ [clarktown.matchers.code-block]
+ [clarktown.renderers.code-block]
+ [clarktown.matchers.list-block]
+ [clarktown.renderers.list-block]
+ [clarktown.renderers.paragraph-block]
+ [clarktown.renderers.link-and-image]
+ [clarktown.renderers.bold]
+ [clarktown.renderers.italic]
+ [clarktown.renderers.inline-code]
+ [clarktown.renderers.strikethrough]))
+
+
+(def
+ ^{:doc "Detects, parses and renders a empty block."}
+ empty-block-parser
+ {:matcher clarktown.matchers.empty-block/match?
+ :renderers [clarktown.renderers.empty-block/render]})
+
+
+(def
+ ^{:doc "Detects, parses and renders a horizontal line block."}
+ horizontal-line-block-parser
+ {:matcher clarktown.matchers.horizontal-line-block/match?
+ :renderers [clarktown.renderers.horizontal-line-block/render]})
+
+
+(def
+ ^{:doc "Detects, parses and renders a heading block."}
+ heading-block-parser
+ {:matcher clarktown.matchers.heading-block/match?
+ :renderers [clarktown.renderers.link-and-image/render
+ clarktown.renderers.bold/render
+ clarktown.renderers.italic/render
+ clarktown.renderers.inline-code/render
+ clarktown.renderers.strikethrough/render
+ clarktown.renderers.heading-block/render]})
+
+
+(def
+ ^{:doc "Detects, parses and renders a quote block."}
+ quote-block-parser
+ {:matcher clarktown.matchers.quote-block/match?
+ :renderers [clarktown.renderers.quote-block/render]})
+
+
+(def
+ ^{:doc "Detects, parses and renders a code block."}
+ code-block-parser
+ {:matcher clarktown.matchers.code-block/match?
+ :renderers [clarktown.renderers.code-block/render]})
+
+
+(def
+ ^{:doc "Detects, parses and renders a list block."}
+ list-block-parser
+ {:matcher clarktown.matchers.list-block/match?
+ :renderers [clarktown.renderers.link-and-image/render
+ clarktown.renderers.bold/render
+ clarktown.renderers.italic/render
+ clarktown.renderers.inline-code/render
+ clarktown.renderers.strikethrough/render
+ clarktown.renderers.list-block/render]})
+
+
+(def
+ ^{:doc "Parses and renders a quote block."}
+ paragraph-block-parser
+ {:renderers [clarktown.renderers.link-and-image/render
+ clarktown.renderers.bold/render
+ clarktown.renderers.italic/render
+ clarktown.renderers.inline-code/render
+ clarktown.renderers.strikethrough/render
+ clarktown.renderers.paragraph-block/render]})
+
+
+(def
+ ^{:doc "A set of default parsers."}
+ default-parsers
+ [empty-block-parser
+ horizontal-line-block-parser
+ heading-block-parser
+ quote-block-parser
+ code-block-parser
+ list-block-parser
+ paragraph-block-parser])
diff --git a/src/clarktown/parsers/horizontal_line_block.clj b/src/clarktown/parsers/horizontal_line_block.clj
deleted file mode 100644
index b1d1e05..0000000
--- a/src/clarktown/parsers/horizontal_line_block.clj
+++ /dev/null
@@ -1,16 +0,0 @@
-(ns clarktown.parsers.horizontal-line-block
- (:require
- [clojure.string :as string]))
-
-
-(defn is?
- "Determines whether the given block is a horizontal line block."
- [block]
- (or (= "***" (string/trim block))
- (= "---" (string/trim block))))
-
-
-(defn render
- "Renders the horizontal line block."
- [_ _]
- "<hr>")
diff --git a/src/clarktown/parsers/bold.clj b/src/clarktown/renderers/bold.clj
index 79579bf..1ce7f84 100644
--- a/src/clarktown/parsers/bold.clj
+++ b/src/clarktown/renderers/bold.clj
@@ -1,4 +1,4 @@
-(ns clarktown.parsers.bold
+(ns clarktown.renderers.bold
(:require
[clojure.string :as string]))
diff --git a/src/clarktown/parsers/code_block.clj b/src/clarktown/renderers/code_block.clj
index c6ecfea..2bed4e6 100644
--- a/src/clarktown/parsers/code_block.clj
+++ b/src/clarktown/renderers/code_block.clj
@@ -1,15 +1,8 @@
-(ns clarktown.parsers.code-block
+(ns clarktown.renderers.code-block
(:require
[clojure.string :as string]))
-(defn is?
- "Determines whether we're dealing with a code block."
- [block]
- (and (string/starts-with? block "```")
- (string/ends-with? block "```")))
-
-
(defn render
"Renders the code block."
[block _]
diff --git a/src/clarktown/renderers/empty_block.clj b/src/clarktown/renderers/empty_block.clj
new file mode 100644
index 0000000..66e819e
--- /dev/null
+++ b/src/clarktown/renderers/empty_block.clj
@@ -0,0 +1,7 @@
+(ns clarktown.renderers.empty-block)
+
+
+(defn render
+ "Renders an empty block."
+ [_ _]
+ "")
diff --git a/src/clarktown/parsers/heading_block.clj b/src/clarktown/renderers/heading_block.clj
index def2394..f953d0a 100644
--- a/src/clarktown/parsers/heading_block.clj
+++ b/src/clarktown/renderers/heading_block.clj
@@ -1,35 +1,10 @@
-(ns clarktown.parsers.heading-block
+(ns clarktown.renderers.heading-block
(:require
- [clojure.string :as string]))
+ [clojure.string :as string]
+ [clarktown.matchers.heading-block :as matcher]))
-(defn is-hashbang-heading?
- "Determines whether the given block is a hashbang heading."
- [block]
- (-> (string/replace block #"\n" "")
- string/trim
- (string/starts-with? "#")))
-
-
-(defn is-settext-heading?
- "Determines whether the given block is a settext heading."
- [block]
- (let [lines (-> (string/split-lines block))
- chars (-> (last lines)
- string/trim
- (string/split #""))]
- (and (> (count lines) 1)
- (every? #{"-" "="} chars))))
-
-
-(defn is?
- "Determines whether the given block is a heading block."
- [block]
- (or (is-hashbang-heading? block)
- (is-settext-heading? block)))
-
-
-(defn render-hashbang-heading
+(defn render-atx-heading
"Renders the hashbang heading block."
[block]
(let [single-line-block (-> (string/replace block #"\n" "")
@@ -61,12 +36,9 @@
(str "<h2>" value "</h2>"))))
-(render-settext-heading "Hello world\nAnd you too\n===")
-
-
(defn render
"Renders the heading block."
[block _]
- (if (is-hashbang-heading? block)
- (render-hashbang-heading block)
+ (if (matcher/is-atx-heading? block)
+ (render-atx-heading block)
(render-settext-heading block)))
diff --git a/src/clarktown/renderers/horizontal_line_block.clj b/src/clarktown/renderers/horizontal_line_block.clj
new file mode 100644
index 0000000..f141e5f
--- /dev/null
+++ b/src/clarktown/renderers/horizontal_line_block.clj
@@ -0,0 +1,7 @@
+(ns clarktown.renderers.horizontal-line-block)
+
+
+(defn render
+ "Renders the horizontal line block."
+ [_ _]
+ "<hr>")
diff --git a/src/clarktown/parsers/inline_code.clj b/src/clarktown/renderers/inline_code.clj
index 1de73bf..29593a8 100644
--- a/src/clarktown/parsers/inline_code.clj
+++ b/src/clarktown/renderers/inline_code.clj
@@ -1,4 +1,4 @@
-(ns clarktown.parsers.inline-code
+(ns clarktown.renderers.inline-code
(:require
[clojure.string :as string]))
diff --git a/src/clarktown/parsers/italic.clj b/src/clarktown/renderers/italic.clj
index 915a017..a1568f6 100644
--- a/src/clarktown/parsers/italic.clj
+++ b/src/clarktown/renderers/italic.clj
@@ -1,4 +1,4 @@
-(ns clarktown.parsers.italic
+(ns clarktown.renderers.italic
(:require
[clojure.string :as string]))
diff --git a/src/clarktown/parsers/link_and_image.clj b/src/clarktown/renderers/link_and_image.clj
index 3be2efe..ea4a006 100644
--- a/src/clarktown/parsers/link_and_image.clj
+++ b/src/clarktown/renderers/link_and_image.clj
@@ -1,4 +1,4 @@
-(ns clarktown.parsers.link-and-image
+(ns clarktown.renderers.link-and-image
(:require
[clojure.string :as string]))
diff --git a/src/clarktown/parsers/list_block.clj b/src/clarktown/renderers/list_block.clj
index 52f955f..2a40b06 100644
--- a/src/clarktown/parsers/list_block.clj
+++ b/src/clarktown/renderers/list_block.clj
@@ -1,15 +1,8 @@
-(ns clarktown.parsers.list-block
+(ns clarktown.renderers.list-block
(:require
[clojure.string :as string]))
-(defn is?
- "Determines whether we're dealing with a list block or not."
- [block]
- (->> (string/trim block)
- (re-matches #"(?s)^(\d\.\s|\*{1}\s|\-{1}\s).*$")))
-
-
(defn string->indent-n
"Returns the indentation count from left of `str`, which must be
in spaces and not tabs."
@@ -111,6 +104,7 @@
(string/starts-with? (:value inner-item) "-")
(-> (string/replace-first (:value inner-item) "-" "")
string/trim)
+ ; ordered list
:else
(-> (string/replace-first (:value inner-item) #"\d\." "")
string/trim))]
diff --git a/src/clarktown/parsers/paragraph_block.clj b/src/clarktown/renderers/paragraph_block.clj
index 3a7c633..c7bec22 100644
--- a/src/clarktown/parsers/paragraph_block.clj
+++ b/src/clarktown/renderers/paragraph_block.clj
@@ -1,4 +1,4 @@
-(ns clarktown.parsers.paragraph-block
+(ns clarktown.renderers.paragraph-block
(:require
[clojure.string :as string]))
diff --git a/src/clarktown/parsers/quote_block.clj b/src/clarktown/renderers/quote_block.clj
index ff2dda8..ee30635 100644
--- a/src/clarktown/parsers/quote_block.clj
+++ b/src/clarktown/renderers/quote_block.clj
@@ -1,17 +1,9 @@
-(ns clarktown.parsers.quote-block
+(ns clarktown.renderers.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]
diff --git a/src/clarktown/parsers/strikethrough.clj b/src/clarktown/renderers/strikethrough.clj
index 6f03152..8e124a0 100644
--- a/src/clarktown/parsers/strikethrough.clj
+++ b/src/clarktown/renderers/strikethrough.clj
@@ -1,4 +1,4 @@
-(ns clarktown.parsers.strikethrough
+(ns clarktown.renderers.strikethrough
(:require
[clojure.string :as string]))