sidenotes.renderer

table of contents

The renderer is responsible for converting parsed contents into html files. It uses clostache templates from a selectable theme folder to create them.

(ns sidenotes.renderer
  (:require
    [sidenotes.fs :as fs]
    [markdown.core :as md]
    [clojure.edn :as edn]
    [clojure.string :as string]
    [clostache.parser :as mustache]))

The folder where internal themes can be found.

(def theme-base "themes/")

The list of internal themes. It would be much nicer if this could be automatically read from the resources of the jar, but so far I have no idea how that could be done.

(def internal-themes ["marginalia" "sidenotes"])

Check that itm is not in itms.

(defn in?
  [itm itms]
  (not (false? (nil? (some #(= itm %) itms)))))

Check if an external theme is sane. It needs to have theme.edn, toc.html and ns.html files.

(defn external-theme-valid?
  [theme-name]
  (and
    (fs/dir? theme-name)
    (fs/file? (str theme-name "/theme.edn"))
    (fs/file? (str theme-name "/toc.html"))
    (fs/file? (str theme-name "/ns.html"))))
(def message-theme-invalid
  "The theme you have provided is not valid. Make sure that it contains the following files:
  theme.edn
  toc.html
  ns.html")

Check if the provided theme is external.

(defn external-theme?
  [theme-name]
  (in? theme-name internal-themes))

Find the path to the used theme.

(defn find-theme
  [theme-name]
  (if (external-theme? theme-name)
    theme-name
    (str theme-base theme-name)))

Transform a dependency so mustache can handle it.

(defn transform-dependency
  [dep]
  {:name (first dep)
   :is-mvn (not (nil? (:mvn/version (second dep))))
   :version (:mvn/version (second dep))
   :is-git (not (nil? (:git/url (second dep))))
   :url (:git/url (second dep))
   :sha (:sha (second dep))})

Transform the list of dependencies for mustache.

(defn transform-dependencies
  [deps]
  (map transform-dependency deps))

Get markdown for an error.

(defn error-md
  [section]
  (str "###ERROR\\n" (:error section)))

Convert stacktrace to code.

(defn stacktrace-code
  [exception]
  (string/join "\\n" (map str (.getStackTrace exception))))

Transform the comments and parse contained markdown.

(defn transform-section
  [section]
  (case (:type section)
    :error (assoc section :docstring (md/md-to-html-string (error-md section)) :raw (stacktrace-code (:exception section)))
    :code (assoc section :docstring (md/md-to-html-string (:docstring section)) :span false)
    :comment (assoc section :docstring (md/md-to-html-string (:raw section)) :raw "" :span true)))

Transform the comments and parse contained markdown.

(defn transform-parsed-source
  [parsed-source]
  (assoc parsed-source
         :sections (map transform-section (:sections parsed-source))
         :is-cljs (= "cljs" (:type parsed-source))
         :is-cljc (= "cljc" (:type parsed-source))
         :is-clj  (= "clj" (:type parsed-source))))

Check if a readme exists and contains markdown. If so convert it to html.

(defn transform-readme
  [readme]
  (if (and (:has-readme readme) (= "md" (:type readme)))
    (assoc readme :html (md/md-to-html-string (:content readme)))
    readme))

Build the parameters for the mustache templates.

(defn toc-template-parameters
  [parsed-sources project settings readme]
  {:settings settings
   :dependencies (transform-dependencies (:deps project))
   :readme (transform-readme readme)
   :sources (map transform-parsed-source parsed-sources)})

Build the parameters for the mustache templates.

(defn ns-template-parameters
  [parsed-source project settings]
  {:settings settings
   :dependencies (transform-dependencies (:deps project))
   :source (transform-parsed-source parsed-source)})

Render the table of contents.

(defn render-toc
  [parsed-sources project settings readme theme external]
  (let [toc-file (str theme "/toc.html")
        toc-template (if external (slurp toc-file) (fs/slurp-resource toc-file))
        filename (str (:output-to settings) "/" (:toc-filename settings))
        tmp (dorun (println (str "Creating table of contents: " filename)))
        params (toc-template-parameters parsed-sources project settings readme)]
    (spit filename (mustache/render toc-template params))))

Render the page for one namespace.

(defn render-ns
  [parsed-source project settings theme external]
  (let [ns-file (str theme "/ns.html")
        ns-template (if external (slurp ns-file) (fs/slurp-resource ns-file))
        filename (str (:output-to settings) "/" (:ns parsed-source) ".html")
        tmp (dorun (println (str " ... rendering to " filename)))
        params (ns-template-parameters parsed-source project settings)]
    (spit filename (mustache/render ns-template params))))

Copy resources from theme to docs folder.

(defn copy-resources
  [settings theme external]
  (dorun (println "Copying resources:"))
  (dorun
    (map #(fs/spit-resource % theme (:output-to settings))
         (:resources
           (edn/read-string
             (fs/slurp-resource (str theme "/theme.edn")))))))

Copy files from theme to docs folder.

(defn copy-files
  [settings theme external]
  (dorun (println "Copying resources:"))
  (dorun
    (map #(fs/copy-file % theme (:output-to settings))
         (:resources
           (edn/read-string
             (slurp (str theme "/theme.edn")))))))

Render the documentation.

(defn render
  [parsed-sources project settings readme]
  (let [theme (find-theme (:theme settings))
        external (external-theme? (:theme settings))]
    (dorun (map #(render-ns % project settings theme external) parsed-sources))
    (render-toc parsed-sources project settings readme theme external)
    (if external
      (copy-files settings theme external)
      (copy-resources settings theme external))))