From d7bc2a899d0a4b70ff9d980e0c05c729278b42f6 Mon Sep 17 00:00:00 2001 From: Nico Rikken Date: Sun, 20 Aug 2017 10:11:16 +0200 Subject: [PATCH] feat(asciidoctor): handle metadata Adds metadata handling to the asciidoctor task. The asciidoctor task will now: 1. read asciidoctor attributes and add them as metadata 2. expose metadata to the asciidoctor process as attributes Both processes are executed independently from each other. --- src/io/perun.clj | 3 +- src/io/perun/asciidoctor.clj | 71 ++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/io/perun.clj b/src/io/perun.clj index 0311681f..c0f6f2e7 100644 --- a/src/io/perun.clj +++ b/src/io/perun.clj @@ -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+ diff --git a/src/io/perun/asciidoctor.clj b/src/io/perun/asciidoctor.clj index 02c52529..c6b4ca91 100644 --- a/src/io/perun/asciidoctor.clj +++ b/src/io/perun/asciidoctor.clj @@ -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)))