Abstract Markup language details and add Asciidoc support:
1. create markup namespace to hold Markup protocol and its Markdown and Asciidoc implementations. 2. Update compiler ns to iterate through available Markups and pass Markup to fns that need Markup info. 3. Refactor compiler ns parse fns to be more granular.
This commit is contained in:
parent
1813848919
commit
b68779fcbe
2 changed files with 105 additions and 69 deletions
|
@ -9,10 +9,9 @@
|
||||||
[clojure.java.io :refer [copy file reader writer]]
|
[clojure.java.io :refer [copy file reader writer]]
|
||||||
[clojure.string :as s]
|
[clojure.string :as s]
|
||||||
[text-decoration.core :refer :all]
|
[text-decoration.core :refer :all]
|
||||||
[markdown.core :refer [md-to-html-string]]
|
|
||||||
[markdown.transformers :refer [transformer-vector]]
|
|
||||||
[cryogen-core.toc :refer [generate-toc]]
|
[cryogen-core.toc :refer [generate-toc]]
|
||||||
[cryogen-core.sass :as sass]))
|
[cryogen-core.sass :as sass]
|
||||||
|
[cryogen-core.markup :as m]))
|
||||||
|
|
||||||
(cache-off!)
|
(cache-off!)
|
||||||
|
|
||||||
|
@ -31,13 +30,13 @@
|
||||||
|
|
||||||
(defn find-posts
|
(defn find-posts
|
||||||
"Returns a list of markdown files representing posts under the post root in templates/md"
|
"Returns a list of markdown files representing posts under the post root in templates/md"
|
||||||
[{:keys [post-root ignored-files]}]
|
[{:keys [post-root ignored-files]} mu]
|
||||||
(find-assets (str "templates/md" post-root) ".md" ignored-files))
|
(find-assets (str "templates/" (m/dir mu) post-root) (m/ext mu) ignored-files))
|
||||||
|
|
||||||
(defn find-pages
|
(defn find-pages
|
||||||
"Returns a list of markdown files representing pages under the page root in templates/md"
|
"Returns a list of markdown files representing pages under the page root in templates/md"
|
||||||
[{:keys [page-root ignored-files]}]
|
[{:keys [page-root ignored-files]} mu]
|
||||||
(find-assets (str "templates/md" page-root) ".md" ignored-files))
|
(find-assets (str "templates/" (m/dir mu) page-root) (m/ext mu) ignored-files))
|
||||||
|
|
||||||
(defn parse-post-date
|
(defn parse-post-date
|
||||||
"Parses the post date from the post's file name and returns the corresponding java date object"
|
"Parses the post date from the post's file name and returns the corresponding java date object"
|
||||||
|
@ -47,13 +46,13 @@
|
||||||
|
|
||||||
(defn post-uri
|
(defn post-uri
|
||||||
"Creates a post uri from the post file name"
|
"Creates a post uri from the post file name"
|
||||||
[file-name {:keys [blog-prefix post-root]}]
|
[file-name {:keys [blog-prefix post-root]} mu]
|
||||||
(str blog-prefix post-root (s/replace file-name #".md" ".html")))
|
(str blog-prefix post-root (s/replace file-name (re-pattern (m/ext mu)) ".html")))
|
||||||
|
|
||||||
(defn page-uri
|
(defn page-uri
|
||||||
"Creates a page uri from the page file name"
|
"Creates a page uri from the page file name"
|
||||||
[page-name {:keys [blog-prefix page-root]}]
|
[page-name {:keys [blog-prefix page-root]} mu]
|
||||||
(str blog-prefix page-root (s/replace page-name #".md" ".html")))
|
(str blog-prefix page-root (s/replace page-name (re-pattern (m/ext mu)) ".html")))
|
||||||
|
|
||||||
(defn read-page-meta
|
(defn read-page-meta
|
||||||
"Returns the clojure map from the top of a markdown page/post"
|
"Returns the clojure map from the top of a markdown page/post"
|
||||||
|
@ -63,65 +62,76 @@
|
||||||
(catch Exception _
|
(catch Exception _
|
||||||
(throw (IllegalArgumentException. (str "Malformed metadata on page: " page))))))
|
(throw (IllegalArgumentException. (str "Malformed metadata on page: " page))))))
|
||||||
|
|
||||||
(defn rewrite-hrefs
|
(defn page-content
|
||||||
"Injects the blog prefix in front of any local links
|
"Returns a map with the given page's file-name, metadata and content parsed from
|
||||||
|
the file with the given markup."
|
||||||
|
[page config markup]
|
||||||
|
(with-open [rdr (java.io.PushbackReader. (reader page))]
|
||||||
|
(let [page-name (.getName page)
|
||||||
|
file-name (s/replace page-name (re-pattern (m/ext markup)) ".html")
|
||||||
|
page-meta (read-page-meta page-name rdr)
|
||||||
|
content ((m/render-fn markup) rdr config)]
|
||||||
|
{:file-name file-name
|
||||||
|
:page-meta page-meta
|
||||||
|
:content content})))
|
||||||
|
|
||||||
ex. <img src='/img/cryogen.png'/> becomes <img src='/blog/img/cryogen.png'/>"
|
(defn merge-meta-and-content
|
||||||
[{:keys [blog-prefix]} text state]
|
"Merges the page metadata and content maps, adding :toc if necessary."
|
||||||
[(clojure.string/replace text #"href=.?/|src=.?/" #(str (subs % 0 (dec (count %))) blog-prefix "/"))
|
[file-name page-meta content]
|
||||||
state])
|
(merge
|
||||||
|
(update-in page-meta [:layout] #(str (name %) ".html"))
|
||||||
(defn parse-content
|
{:file-name file-name
|
||||||
"Parses the markdown content in a post/page into html"
|
:content content
|
||||||
[rdr config]
|
:toc (if (:toc page-meta) (generate-toc content))}))
|
||||||
(md-to-html-string
|
|
||||||
(->> (java.io.BufferedReader. rdr)
|
|
||||||
(line-seq)
|
|
||||||
(s/join "\n"))
|
|
||||||
:reference-links? true
|
|
||||||
:heading-anchors true
|
|
||||||
:replacement-transformers (conj transformer-vector (partial rewrite-hrefs config))))
|
|
||||||
|
|
||||||
(defn parse-page
|
(defn parse-page
|
||||||
"Parses a page/post and returns a map of the content, uri, date etc."
|
"Parses a page/post and returns a map of the content, uri, date etc."
|
||||||
[is-post? page config]
|
[page config markup]
|
||||||
(with-open [rdr (java.io.PushbackReader. (reader page))]
|
(let [{:keys [file-name page-meta content]} (page-content page config markup)]
|
||||||
(let [page-name (.getName page)
|
(merge
|
||||||
file-name (s/replace page-name #".md" ".html")
|
(merge-meta-and-content file-name page-meta content)
|
||||||
page-meta (read-page-meta page-name rdr)
|
{:uri (page-uri file-name config markup)
|
||||||
content (parse-content rdr config)]
|
:page-index (:page-index page-meta)})))
|
||||||
(merge
|
|
||||||
(update-in page-meta [:layout] #(str (name %) ".html"))
|
(defn parse-post
|
||||||
{:file-name file-name
|
"Return a map with the given post's information."
|
||||||
:content content
|
[page config markup]
|
||||||
:toc (if (:toc page-meta) (generate-toc content))}
|
(let [{:keys [file-name page-meta content]} (page-content page config markup)]
|
||||||
(if is-post?
|
(merge
|
||||||
(let [date (parse-post-date file-name (:post-date-format config))
|
(merge-meta-and-content file-name page-meta content)
|
||||||
archive-fmt (java.text.SimpleDateFormat. "yyyy MMMM" (java.util.Locale. "en"))
|
(let [date (parse-post-date file-name (:post-date-format config))
|
||||||
formatted-group (.format archive-fmt date)]
|
archive-fmt (java.text.SimpleDateFormat. "yyyy MMMM" (java.util.Locale. "en"))
|
||||||
{:date date
|
formatted-group (.format archive-fmt date)]
|
||||||
:formatted-archive-group formatted-group
|
{:date date
|
||||||
:parsed-archive-group (.parse archive-fmt formatted-group)
|
:formatted-archive-group formatted-group
|
||||||
:uri (post-uri file-name config)
|
:parsed-archive-group (.parse archive-fmt formatted-group)
|
||||||
:tags (set (:tags page-meta))})
|
:uri (post-uri file-name config markup)
|
||||||
{:uri (page-uri file-name config)
|
:tags (set (:tags page-meta))})
|
||||||
:page-index (:page-index page-meta)})))))
|
)))
|
||||||
|
|
||||||
(defn read-posts
|
(defn read-posts
|
||||||
"Returns a sequence of maps representing the data from markdown files of posts.
|
"Returns a sequence of maps representing the data from markdown files of posts.
|
||||||
Sorts the sequence by post date."
|
Sorts the sequence by post date."
|
||||||
[config]
|
[config]
|
||||||
(->> (find-posts config)
|
(->> (mapcat
|
||||||
(map #(parse-page true % config))
|
(fn [mu]
|
||||||
|
(->>
|
||||||
|
(find-posts config mu)
|
||||||
|
(map #(parse-post % config mu))))
|
||||||
|
(m/markups))
|
||||||
(sort-by :date)
|
(sort-by :date)
|
||||||
reverse))
|
reverse))
|
||||||
|
|
||||||
(defn read-pages
|
(defn read-pages
|
||||||
"Returns a sequence of maps representing the data from markdown files of pages.
|
"Returns a sequence of maps representing the data from markdown files of pages.
|
||||||
Sorts the sequence by post date."
|
Sorts the sequence by post date."
|
||||||
[config]
|
[config]
|
||||||
(->> (find-pages config)
|
(->> (mapcat
|
||||||
(map #(parse-page false % config))
|
(fn [mu]
|
||||||
|
(->>
|
||||||
|
(find-pages config mu)
|
||||||
|
(map #(parse-page % config mu))))
|
||||||
|
(m/markups))
|
||||||
(sort-by :page-index)))
|
(sort-by :page-index)))
|
||||||
|
|
||||||
(defn tag-post
|
(defn tag-post
|
||||||
|
|
|
@ -1,37 +1,63 @@
|
||||||
(ns cryogen-core.markup
|
(ns cryogen-core.markup
|
||||||
(:require [markdown.core :refer [md-to-html-string]]
|
(:require [markdown.core :refer [md-to-html-string]]
|
||||||
|
[markdown.transformers :refer [transformer-vector]]
|
||||||
[clojure.string :as s])
|
[clojure.string :as s])
|
||||||
(:import org.asciidoctor.Asciidoctor$Factory
|
(:import org.asciidoctor.Asciidoctor$Factory
|
||||||
java.util.Collections))
|
java.util.Collections))
|
||||||
|
|
||||||
(defprotocol Markup
|
(defprotocol Markup
|
||||||
|
"A markup engine comprising a dir(ectory) containing markup files,
|
||||||
|
an ext(ension) for finding markup file names, and a render-fn that returns
|
||||||
|
a fn with the signature [java.io.Reader config] -> String (HTML)."
|
||||||
(dir [this])
|
(dir [this])
|
||||||
(ext [this])
|
(ext [this])
|
||||||
(render-fn [this]))
|
(render-fn [this]))
|
||||||
|
|
||||||
(defn- markdown []
|
(defn- rewrite-hrefs
|
||||||
|
"Injects the blog prefix in front of any local links
|
||||||
|
|
||||||
|
ex. <img src='/img/cryogen.png'/> becomes <img src='/blog/img/cryogen.png'/>"
|
||||||
|
[{:keys [blog-prefix]} text state]
|
||||||
|
[(clojure.string/replace text #"href=.?/|src=.?/" #(str (subs % 0 (dec (count %))) blog-prefix "/"))
|
||||||
|
state])
|
||||||
|
|
||||||
|
(defn- markdown
|
||||||
|
"Returns a Markdown (https://daringfireball.net/projects/markdown/)
|
||||||
|
implementation of the Markup protocol."
|
||||||
|
[]
|
||||||
(reify Markup
|
(reify Markup
|
||||||
(dir [this] "md")
|
(dir [this] "md")
|
||||||
(ext [this] ".md")
|
(ext [this] ".md")
|
||||||
(render-fn [this]
|
(render-fn [this]
|
||||||
(fn [rdr]
|
(fn [rdr config]
|
||||||
(md-to-html-string
|
(md-to-html-string
|
||||||
(->> (java.io.BufferedReader. rdr)
|
(->> (java.io.BufferedReader. rdr)
|
||||||
(line-seq)
|
(line-seq)
|
||||||
(s/join "\n"))
|
(s/join "\n"))
|
||||||
:heading-anchors true)))))
|
:reference-links? true
|
||||||
|
:heading-anchors true
|
||||||
|
:replacement-transformers (conj transformer-vector (partial rewrite-hrefs config)))))))
|
||||||
|
|
||||||
(defn- asciidoc []
|
(defn- asciidoc
|
||||||
|
"Returns an Asciidoc (http://asciidoc.org/) implementation of the
|
||||||
|
Markup protocol."
|
||||||
|
[]
|
||||||
(reify Markup
|
(reify Markup
|
||||||
(dir [this] "asc")
|
(dir [this] "asc")
|
||||||
(ext [this] ".asc")
|
(ext [this] ".asc")
|
||||||
(render-fn [this]
|
(render-fn [this]
|
||||||
(fn [rdr]
|
(let [attributes (java.util.HashMap. {"toc" "macro"})
|
||||||
(.convert (Asciidoctor$Factory/create)
|
options (java.util.HashMap. {"attributes" attributes})]
|
||||||
(->> (java.io.BufferedReader. rdr)
|
(fn [rdr _]
|
||||||
(line-seq)
|
(.convert (Asciidoctor$Factory/create)
|
||||||
(s/join "\n"))
|
(->> (java.io.BufferedReader. rdr)
|
||||||
(Collections/emptyMap))))))
|
(line-seq)
|
||||||
|
(s/join "\n"))
|
||||||
|
options))))))
|
||||||
|
|
||||||
(defn markups []
|
(defn markups
|
||||||
|
"Return a vector of Markup implementations. This is the primary entry point
|
||||||
|
for a client of this ns. This vector should be used to iterate over supported
|
||||||
|
Markups."
|
||||||
|
[]
|
||||||
[(markdown) (asciidoc)])
|
[(markdown) (asciidoc)])
|
||||||
|
|
Loading…
Reference in a new issue