Skip to content

A cross-platform clojure/script parser for Markdown

License

Notifications You must be signed in to change notification settings

defsquare/markdown

 
 

Repository files navigation

nextjournal markdown

Clojars Project Notebooks

A cross-platform clojure library for Markdown parsing and transformation.

🚧 ALPHA status, subject to frequent change. For a richer reading experience read this readme as a clerk notebook.

Features

  • Focus on data: parsing yields an AST (à la Pandoc) of nested data representing a structured document.
  • Cross Platform: clojurescript native, we target the JVM using Graal's Polyglot Library.
  • Configurable Hiccup conversion.

Try

Try it online.

Flavor

By building on top of markdown-it, we adhere to CommonMark Spec (with some exceptions1) and also comply with extensions from Github flavoured Markdown. Additionally, we parse $\LaTeX$ formulas (delimited by a $ for inline rendering or $$ for display mode).

For more details you might have a look at the set of plugins we're using.

Usage

(ns hello-markdown
  (:require [nextjournal.markdown :as md]
            [nextjournal.markdown.transform :as md.transform]))

Parsing markdown into an AST:

(def data 
  (md/parse "> et tout autour, la longue cohorte de ses personnages, avec leur histoire, leur passé, leurs légendes:
> 1. Pélage vainqueur d'Alkhamah se faisant couronner à Covadonga
> 2. La cantatrice exilée de Russie suivant Schönberg à Amsterdam
> 3. Le petit chat sourd aux yeux vairons vivant au dernier étage
> 4. ...

**Georges Perec**, _La Vie mode d'emploi_.

---
"))
;; =>
{:type :doc,
 :content [{:type :blockquote,
            :content [{:type :paragraph,
                       :content [{:type :text,
                                  :text "et tout autour, la longue cohorte de ses personnage, avec leur histoire, leur passé, leurs légendes:"}]}
                      {:type :numbered-list,
                       :content [{:type :list-item,
                                  :content [{:type :plain,
                                             :content [{:type :text,
                                                        :text "Pélage vainqueur d'Alkhamah se faisant couronner à Covadonga"}]}]}
                                 {:type :list-item,
                                  :content [{:type :plain,
                                             :content [{:type :text,
                                                        :text "La cantatrice exilée de Russie suivant Schönberg à Amsterdam"}]}]}
                                 {:type :list-item,
                                  :content [{:type :plain,
                                             :content [{:type :text,
                                                        :text "Le petit chat sourd aux yeux vairons vivant au dernier étage"}]}]}]}]}
           {:type :paragraph,
            :content [{:type :strong, :content [{:type :text, :text "Georges Perec"}]}
                      {:type :text, :text ", "}
                      {:type :em, :content [{:type :text, :text "La Vie mode d'emploi"}]}
                      {:type :text, :text "."}]}
           {:type :ruler}]}

and transform that AST into hiccup syntax.

(md.transform/->hiccup data)
;; =>
[:div
 [:blockquote
  [:p "et tout autour, la longue cohorte de ses personnage, avec leur histoire, leur passé, leurs légendes:"]
  [:ol
   [:li [:<> "Pélage vainqueur d'Alkhamah se faisant couronner à Covadonga"]]
   [:li [:<> "La cantatrice exilée de Russie suivant Schönberg à Amsterdam"]]
   [:li [:<> "Le petit chat sourd aux yeux vairons vivant au dernier étage"]]]]
 [:p [:strong "Georges Perec"] ", " [:em "La Vie mode d'emploi"] "."]
 [:hr]]

We've built hiccup transformation in for convenience, but the same approach can be used to target more formats.

This library is one of the building blocks of Clerk where it is used for rendering literate fragments.

^{:nextjournal.clerk/viewer 'nextjournal.clerk.viewer/markdown-viewer}
data

The transformation of markdown node types can be customised like this:

^{:nextjournal.clerk/viewer 'nextjournal.clerk.viewer/html-viewer}
(md.transform/->hiccup
 (assoc md.transform/default-hiccup-renderers
        ;; :doc specify a custom container for the whole doc
        :doc (partial md.transform/into-markup [:div.viewer-markdown])
        ;; :text is funkier when it's zinc toned 
        :text (fn [_ctx node] [:span {:style {:color "#71717a"}} (:text node)])
        ;; :plain fragments might be nice, but paragraphs help when no reagent is at hand
        :plain (partial md.transform/into-markup [:p {:style {:margin-top "-1.2rem"}}])
        ;; :ruler gets to be funky, too
        :ruler (constantly [:hr {:style {:border "2px dashed #71717a"}}]))
 data)

Extensibility

We added minimal tooling for extending markdown expressions.

Footnotes

  1. isolated images are not wrapped in a paragraph node, unless they're part of inline content. See more examples in this notebook.

About

A cross-platform clojure/script parser for Markdown

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Clojure 97.8%
  • JavaScript 1.4%
  • HTML 0.8%