Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(asciidoctor): handle metadata #191

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/io/perun.clj
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,8 @@
:cmd-opts cmd-opts))))

(def ^:private ^:deps asciidoctor-deps
'[[org.clojure/tools.namespace "0.3.0-alpha3"]
'[[clj-time "0.14.0"]
[org.clojure/tools.namespace "0.3.0-alpha3"]
[org.asciidoctor/asciidoctorj "1.5.4"]])

(def ^:private +asciidoctor-defaults+
Expand Down
71 changes: 67 additions & 4 deletions src/io/perun/asciidoctor.clj
Original file line number Diff line number Diff line change
@@ -1,16 +1,79 @@
(ns io.perun.asciidoctor
(:require [io.perun.core :as perun]
[clj-time.coerce :as tc]
[clj-time.format :as tf]
[clojure.java.io :as io])
(:import [org.asciidoctor Asciidoctor Asciidoctor$Factory]))

(defn keywords->names
"Converts a map with keywords to a map with named keys. Only handles the top
level of any nested structure."
[m]
(reduce-kv #(assoc %1 (name %2) %3) {} m))

(defn names->keywords
"Converts a map with named keys to a map with keywords. Only handles the top
level of any nested structure."
[m]
(reduce-kv #(assoc %1 (keyword %2) %3) {} m))

(def container
(Asciidoctor$Factory/create ""))

(defn asciidoctor-to-html [file-content]
(.convert container file-content {}))
(defn meta->attributes
"Takes the Perun meta and converts it to a collection of attributes, which can
be handed to the AsciidoctorJ process."
[meta]
(-> meta
keywords->names
(java.util.HashMap.)))

(defn parse-date
"Tries to parse a date string into a DateTime object"
[date]
(when date
(if-let [parsed (tc/to-date date)]
parsed
(perun/report-info "asciidoctor" "failed to parse date %s" date))))

(defn attributes->meta
"Add duplicate entries for the metadata keys gathered from the AsciidoctorJ
parsing using keys that adhere to the Perun specification of keys. The native
AsciidoctorJ keys are still available."
[attributes]
(let [meta (names->keywords (into {} attributes))]
(merge meta
{:author-email (:email meta)
:title (:doctitle meta)
:date-published (parse-date (:revdate meta))})))

(defn protect-meta
"Strip keywords from metadata that are being used by Perun to properly
function."
[meta]
(dissoc meta
:canonical-url :extension :filename :full-path :parent-path :permalink
:short-filename :slug))

(defn parse-file-metadata
"Processes the asciidoctor content and extracts all the attributes."
[adoc-content]
(->> (.readDocumentStructure container adoc-content {})
(.getHeader)
(.getAttributes)
attributes->meta
protect-meta))

(defn asciidoctor-to-html [file-content attributes]
(let [options (if attributes
{"attributes" attributes}
{})]
(.convert container file-content options)))

(defn process-asciidoctor [{:keys [entry]}]
(perun/report-debug "asciidoctor" "processing asciidoctor" (:filename entry))
(let [file-content (-> entry :full-path io/file slurp)
html (asciidoctor-to-html file-content)]
(assoc entry :rendered html)))
attributes (meta->attributes entry)
html (asciidoctor-to-html file-content attributes)
meta (parse-file-metadata file-content)]
(merge (assoc entry :rendered html) meta)))