{"id":13591896,"url":"https://github.com/yogthos/markdown-clj","last_synced_at":"2025-05-13T23:06:55.881Z","repository":{"id":1020828,"uuid":"2551308","full_name":"yogthos/markdown-clj","owner":"yogthos","description":"Markdown parser in Clojure","archived":false,"fork":false,"pushed_at":"2025-02-07T14:15:08.000Z","size":1478,"stargazers_count":555,"open_issues_count":26,"forks_count":121,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-03T01:04:44.564Z","etag":null,"topics":["clojure-library","clojurescript","markdown-parser"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yogthos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"yogthos"}},"created_at":"2011-10-10T21:45:56.000Z","updated_at":"2025-04-23T02:10:34.000Z","dependencies_parsed_at":"2024-11-19T12:12:15.981Z","dependency_job_id":"a2d56548-1c5c-4750-ba7f-0a9a0d075fd0","html_url":"https://github.com/yogthos/markdown-clj","commit_stats":{"total_commits":458,"total_committers":54,"mean_commits":8.481481481481481,"dds":"0.25764192139737996","last_synced_commit":"288a19b983b06fa1b12a99f0773956e420f998e4"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yogthos%2Fmarkdown-clj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yogthos%2Fmarkdown-clj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yogthos%2Fmarkdown-clj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yogthos%2Fmarkdown-clj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yogthos","download_url":"https://codeload.github.com/yogthos/markdown-clj/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254040676,"owners_count":22004592,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure-library","clojurescript","markdown-parser"],"created_at":"2024-08-01T16:01:03.428Z","updated_at":"2025-05-13T23:06:50.865Z","avatar_url":"https://github.com/yogthos.png","language":"Clojure","funding_links":["https://github.com/sponsors/yogthos"],"categories":["Clojure","Awesome ClojureScript"],"sub_categories":["Miscellaneous"],"readme":"# Markdown parser written in Clojure/Script\n\n[![CircleCI](https://circleci.com/gh/yogthos/markdown-clj.svg?style=svg)](https://circleci.com/gh/yogthos/markdown-clj) [![Downloads](https://jarkeeper.com/yogthos/markdown-clj/downloads.svg)](https://jarkeeper.com/yogthos/markdown-clj)\n\n## Demo\n\nYou can try out the parser [here](https://rawgit.com/yogthos/markdown-clj/master/demo/markdown.html).\n\n## Building Js artifact\n\nrun `lein with-profile js cljsbuild once` this will create a standalone `js/markdown.js` artifact.\n\n## Installation\n\nA markdown parser that compiles to both Clojure and ClojureScript.\n\n[![Clojars Project](http://clojars.org/markdown-clj/latest-version.svg)](http://clojars.org/markdown-clj)\n\nNote: `markdown-clj` versions prior to `0.9.68` requires Clojure 1.2+ to run, versions `0.9.68+` require Clojure 1.7.\n\n[![NPM](https://nodei.co/npm/markdown-clj.png?mini=true)](https://www.npmjs.com/package/markdown-clj)\n\n## Usage Clojure\n\nMarkdown-clj can be invoked either by calling `md-to-html` or `md-to-html-string` functions.\n\nThe `md-to-html` function accepts an input containing Markdown markup and an output where\nthe resulting HTML will be written. The input and output parameters will be passed to a reader\nand a writer respectively:\n\n```clojure\n(ns foo\n  (:use markdown.core))\n\n(md-to-html \"input.md\" \"output.html\")\n\n(md-to-html (input-stream \"input.md\") (output-stream \"test.txt\"))\n```\n\nThe `md-to-html-string` function accepts a string with markdown content and returns a string with the resulting HTML:\n\n```clojure\n(md-to-html-string \"# This is a test\\nsome code follows\\n```clojure\\n(defn foo [])\\n```\")\n```\n```xml\n\u003ch1\u003e This is a test\u003c/h1\u003esome code follows\u003cpre\u003e\u003ccode class=\"clojure\"\u003e\u0026#40;defn foo \u0026#91;\u0026#93;\u0026#41;\n\u003c/code\u003e\u003c/pre\u003e\n```\n\nBoth `md-to-html` and `md-to-html-string` accept optional parameters:\n\nSpecifying `:heading-anchors` will create anchors for the heading tags, eg:\n\n```clojure\n(markdown/md-to-html-string \"###foo bar BAz\" :heading-anchors true)\n\n```\n```xml\n\u003ch3 id=\\\"foo\u0026#95;bar\u0026#95;baz\\\"\u003efoo bar BAz\u003c/h3\u003e\n```\n\nThe code blocks default to a [highlight.js](https://highlightjs.org/) compatible format of:\n```xml\n\u003cpre\u003e\u003ccode class=\"clojure\"\u003esome code\u003c/code\u003e\u003c/pre\u003e\n```\n\nSpecifying `:code-style` will override the default code class formatting for code blocks, eg:\n\n```clojure\n(md-to-html-string \"# This is a test\\nsome code follows\\n```clojure\\n(defn foo [])\\n```\"\n                   :code-style #(str \"class=\\\"brush: \" % \"\\\"\"))\n```\n```xml\n\u003ch1\u003e This is a test\u003c/h1\u003esome code follows\u003cpre\u003e\u003ccode class=\"brush: clojure\"\u003e\n\u0026#40;defn foo \u0026#91;\u0026#93;\u0026#41;\n\u003c/code\u003e\u003c/pre\u003e\n```\n\nSpecifying `:pre-style` will override the default pre class formatting.\n\n```clojure\n(md-to-html-string \"# This is a test\\nsome code follows\\n```clojure\\n(defn foo [])\\n```\"\n                   :pre-style #(str \"class=\\\"brush: \" % \"\\\"\"))\n```\n```xml\n\u003ch1\u003e This is a test\u003c/h1\u003esome code follows\u003cpre class=\"brush: clojure\"\u003e\u003ccode\u003e\n\u0026#40;defn foo \u0026#91;\u0026#93;\u0026#41;\n\u003c/code\u003e\u003c/pre\u003e\n```\n\n### Reference style links\n\nThe parser defaults to using inline reference for performance reasons, to enable reference style links pass in the `:reference-links? true` option:\n\n```clojure\n(md-to-html-string\n  \"This is [an example][id] reference-style link.\n\n   [id]: http://example.com/ 'Optional Title Here'\"\n   :reference-links? true)\n```\n\n### Footnotes\n\nTo enable footnotes, pass the `:footnotes? true` option:\n\n```clojure\n(md-to-html-string\n  \"Footnotes will appear automatically numbered with a link to the footnote at bottom of the page [^footnote1].\n\n  [^footnote1]: The footnote will contain a back link to to the referring text.\"\n  :footnotes? true)\n```\n\n### Metadata\n\nThe metadata encoded using the syntax described by [MultiMarkdown](https://github.com/fletcher/MultiMarkdown/wiki/MultiMarkdown-Syntax-Guide#metadata) can be optionally extracted from the document.\n\nThe `md-to-html` function will attempt to parse the metadata when passed the `:parse-meta? true` option and return it as its output.\nAdditionally, `md-to-html-string-with-meta` function can be used to parse string input. The function returns a map with two keys, `:html` containing the parsed HTML, and `:metadata` containing a map with the metadata included at the top of the document.\n\nTo parse *only* the metadata, use `md-to-meta`.  This function returns a metadata map for the given input, but does not otherwise parse the Markdown or return HTML. It can run more quickly than either of the functions that return HTML and can be useful in scenarios where the metadata can be useful by itself.\n\nThe value of each key in the metadata map will be a list of either 0, 1 or many strings. If a metadata value ends in two spaces then the string will end in a newline. If a line does not contain a header and has at least 4 spaces in front of it then it will be considered to be a member of the last key that was found.\n\n```clojure\n(let [input    (new StringReader text)\n      output   (new StringWriter)\n      metadata (md-to-html input output :parse-meta? true)\n      html     (.toString output)]\n  {:metadata metadata :html html})\n\n(md-to-html-string-with-meta\n  \"Author: Rexella van Imp\n    Kim Jong-un\nDate: October 31, 2015\n\n   # Hello!\")\n\n{:metadata {:author [\"Rexella van Imp\"\n                     \"Kim Jong-un\"],\n            :date [\"October 31, 2015\"]},\n :html \"\u003ch1\u003eHello!\u003c/h1\u003e\"}\n```\n\n### Selectively inhibiting the Parser\n\nIf you pass `:inhibit-separator \"some-string\"`, then any text within occurrences of `some-string` will be output verbatim, eg:\n\n```clojure\n(md-to-html-string \"For all %$a_0, a_1, ..., a_n in R$% there is _at least one_ %$b_n in R$% such that...\"\n                   :inhibit-separator \"%\")\n```\n```xml\nFor all $a_0, a_1, ..., a_n in R$ there is \u003ci\u003eat least one\u003c/i\u003e $b_n in R$ such that...\n```\n\nThis may be useful to use `markdown-clj` along with other parsers of languages with conflicting syntax (e.g. asciimath2jax).\n\nIf you need to output the separator itself, enter it twice without any text inside.  Eg:\n\n```clojure\n(md-to-html-string \"This is one of those 20%% vs 80%% cases.\"\n                   :inhibit-separator \"%\")\n```\n```xml\nThis is one of those 20% vs 80% cases.\n```\n\nSome caveats:\n\n- Like other tags, this only works within a single line.\n\n- If you remove the default transformers with `:replacement-transformers` (which see below), inhibiting will stop working.\n\n- Currently, dashes (`--` and `---`) can't be suppressed this way.\n\n## Customizing the Parser\n\nAdditional transformers can be specified using the `:custom-transformers` key.\nA transformer function must accept two arguments.\nFirst argument is the string representing the current line and the second is the map representing the current state.\n\nThe default state keys are:\n\n* `:code` - inside a code section\n* `:codeblock` - inside a code block\n* `:eof` - end of file\n* `:heading` - in a heading\n* `:hr` - in a horizontal line\n* `:lists` - inside a list\n* `:blockquote` - inside a blockquote\n* `:paragraph` - in a paragraph\n* `:last-line-empty?` - was last line an empty line?\n\nFor example, if we wanted to add a transformer that would capitalize all text we could do the following:\n\n```clojure\n(defn capitalize [text state]\n  [(.toUpperCase text) state])\n\n(markdown/md-to-html-string \"#foo\" :custom-transformers [capitalize])\n```\n\n```xml\n\u003cH1\u003eFOO\u003c/H1\u003e\n```\n\nAlternatively, you could provide a custom set of transformers to replace the default transformers using the `:replacement-transformers` key.\n\n```clojure\n(markdown/md-to-html-string \"#foo\" :replacement-transformers [capitalize])\n```\n\nThis can also be used to add preprocessor transformers. For example, if we wanted to sanitize any image links and escape HTML we could do the following:\n\n```clojure\n(use 'markdown.transformers 'markdown.core)\n\n(defn escape-images [text state]\n  [(clojure.string/replace text #\"(!\\[.*?\\]\\()(.+?)(\\))\" \"\") state])\n\n(defn escape-html\n    \"Change special characters into HTML character entities.\"\n    [text state]\n    [(if-not (or (:code state) (:codeblock state))\n       (clojure.string/escape\n         text\n         {\\\u0026 \"\u0026amp;\"\n          \\\u003c \"\u0026lt;\"\n          \\\u003e \"\u0026gt;\"\n          \\\" \"\u0026quot;\"\n          \\' \"\u0026#39;\"})\n       text) state])\n       \n(markdown/md-to-html-string\n  \"\u003ch1\u003eescaped\u003c/h1\u003efoo ![Alt text](/path/to/img.jpg \\\"Optional Title\\\") bar [text](http://test)\"\n  :replacement-transformers (into [escape-images escape-html] transformer-vector))\n```\n\n```xml\n\"\u003cp\u003e\u0026lt;h1\u0026gt;escaped\u0026lt;/h1\u0026gt;foo  bar \u003ca href='http://test'\u003etext\u003c/a\u003e\u003c/p\u003e\"\n```\n\n### Codeblock callbacks\n\nIt's possible to pass a `:codeblock-callback` function to the parser that will\npostprocess the code as follows: \n\nYou can also pass `:codeblock-no-escape? true` to disable code escaping.\n\n```clojure\n(markdown/md-to-html-string \"```python\\ndef f(x):\\n    return x * 2\\n```\"\n                       :codeblock-no-escape? true\n                       :codeblock-callback (fn\n                                             [code language]\n                                             (clygments/highlight code language :html)))\n```\n\n## Usage ClojureScript\n\nThe ClojureScript portion works the same as above except that the entry function is called `md-\u003ehtml`. It accepts\na string followed by the options as its input, and returns the resulting HTML string:\n\n```clojure\n(ns myscript\n  (:require [markdown.core :refer [md-\u003ehtml]]))\n\n(.log js/console\n  (md-\u003ehtml \"##This is a heading\\nwith a paragraph following it\"))\n\n(.log js/console\n  (md-\u003ehtml \"# This is a test\\nsome code follows\\n```clojure\\n(defn foo [])\\n```\"\n               :code-style #(str \"class=\\\"\" % \"\\\"\")))\n\n(md-\u003ehtml-with-meta \"# This is a test\\nsome code follows\\n```clojure\\n(defn foo [])\\n```\")\n```\n\n## Usage JavaScript\n\n```javascript\nconsole.log(markdown.core.mdToHtml(\"##This is a heading\\nwith a paragraph following it\"));\n\n// With keyword arguments\nconsole.log(markdown.core.mdToHtml(\"##This is a heading\\nwith a paragraph following it\", \"heading-anchors\", true));\n\n```\n\n## Supported syntax\n\nControl characters can be escaped using \\\n```\n\\\\ backslash\n\\` backtick\n\\* asterisk\n\\_ underscore\n\\{ curly braces\n\\}\n\\[ square brackets\n\\]\n\\( parentheses\n\\)\n\\# hash mark\n\\+ plus sign\n\\- minus sign (hyphen)\n\\. dot\n\\! exclamation mark\n\\^ caret / circumflex accent\n```\n\n#### Basic Elements\n[Blockquote](#blockquote),\n[Strong](#strong),\n[Bold](#bold),\n[Bold-Italic](#bold-italic),\n[Emphasis](#emphasis),\n[Italics](#italics),\n[Heading](#heading),\n[Line](#line),\n[Linebreak](#linebreak),\n[Paragraph](#paragraph),\n[Strikethrough](#strikethrough)\n\n#### Links\n[Image](#image),\n[Link](#link)\n\n##### Automatic Links\n\nThis is a shortcut style for creating \u0026#8220;automatic\u0026#8221; links for URLs and email addresses:\n\n```\n\u003chttp://example.com/\u003e\n```\nwill be turned this into:\n\n```\n\u003ca href=\"http://example.com/\"\u003ehttp://example.com/\u003c/a\u003e\n```\n\nAutomatic links for email addresses work similarly, except that they are hex encoded:\n\n```\n\u003caddress@example.com\u0026\u003e\n```\n\nwill be turned into:\n\n```\n\u003ca href=\\\"\u0026#x61\u0026#x64\u0026#x64\u0026#x72\u0026#x65\u0026#x73\u0026#x73\u0026#x40\u0026#x65\u0026#x78\u0026#x61\u0026#x6d\u0026#x70\u0026#x6c\u0026#x65\u0026#x2e\u0026#x63\u0026#x6f\u0026#x6d\\\"\u003e\u0026#x61\u0026#x64\u0026#x64\u0026#x72\u0026#x65\u0026#x73\u0026#x73\u0026#x40\u0026#x65\u0026#x78\u0026#x61\u0026#x6d\u0026#x70\u0026#x6c\u0026#x65\u0026#x2e\u0026#x63\u0026#x6f\u0026#x6d\u003c/a\u003e\n```\n\n#### Lists\n[Ordered List](#ordered-list),\n[Unordered List](#unordered-list)\n\n#### Code\n[Code Block](#code-block),\n[Indented Code](#indented-code),\n[Inline Code](#inline-code)\n\n***\n\n### Heading\n\nthe number of hashes indicates the level of the heading\n\n```\n# Heading\n\n##Sub-heading\n\n### Sub-sub-heading\n```\n\nheadings can also be defined using `=` and `-` for `h1` and `h2` respectively\n\n```\nHeading 1\n=========\n\nHeading 2\n---------\n```\n\n### Line\n\n```\n***\n\n* * *\n\n*****\n\n- - -\n\n______\n```\n\n### Linebreak\n\nIf a line ends with two or more spaces a `\u003cbr /\u003e` tag will be inserted at the end.\n\n### Emphasis\n\n```\n*foo*\n```\n\n### Italics\n\n```\n_foo_\n```\n\n### Strong\n\n```\n**foo**\n```\n\n### Bold\n\n```\n__foo__\n```\n\n### Bold-Italic\n```\n***bold italic***\n```\n\n### Blockquote\n`\u003e` prefixes regular blockquote paragraphs.  `\u003e-` prefixes a\nblockquote footer that can be used for author attribution.\n\n```\n\u003eThis is a blockquote\nwith some content\n\n\u003ethis is another blockquote\n\n\u003e Everyone thinks of changing the world,\nbut no one thinks of changing himself.\n\u003e- Leo Tolstoy\n```\n\n### Paragraph\n\n```\nThis is a paragraph, it's\nsplit into separate lines.\n\nThis is another paragraph.\n\n```\n\n### Unordered List\n\nindenting an item makes it into a sublist of the item above it, ordered and unordered lists can be nested within one another.\nList items can be split over multiple lines.\n\n```\n* Foo\n* Bar\n * Baz\n```\n\n```\n* foo\n* bar\n\n   * baz\n     1. foo\n     2. bar\n        more content\n        ## subheading\n        ***\n        **strong text** in the list\n\n   * fuzz\n\n      * blah\n      * blue\n* brass\n```\n\n### Ordered List\n\n```\n1. Foo\n2. Bar\n3. Baz\n```\n\n### Inline Code\n\nAny special characters in code will be escaped with their corresponding HTML codes.\n\n```\nHere's some code `x + y = z` that's inlined.\n```\n\n### Code block\n\nUsing three backquotes indicates a start of a code block, the next three backquotes ends the code block section.\nOptionally, the language name can be put after the backquotes to produce a tag compatible with [highlight.js](https://highlightjs.org/), eg:\n\n\u0026#96;\u0026#96;\u0026#96;clojure\n\n(defn foo [bar] \"baz\")\n\n\u0026#96;\u0026#96;\u0026#96;\n\n\n### Indented Code\n\nindenting by at least 4 spaces creates a code block\n\n    some\n    code\n    here\n\nnote: XML is escaped in code sections\n\n### Strikethrough\n\n```\n~~foo~~\n```\n\n### Superscript\n\n```\na^2 + b^2 = c^2\n```\n\n### Link\n```\n[github](http://github.com)\n```\n\n##### Reference Link\n\n```\nThis is [an example][id] reference-style link.\n\n[id]: http://example.com/  \"Optional Title Here\"\n```\n\nnote: reference links require the `:reference-links?` option to be set to true\n\n### Footnote\n\n```\n\"Footnotes will appear automatically numbered with a link to the footnote at bottom of the page [^footnote1].\n[^footnote1]: The footnote will contain a back link to to the referring text.\"\n```\n\nnote: to enable footnotes, the `:footnotes?` option must be set to true.\n\n### Image\n```\n![Alt text](http://server/path/to/img.jpg)\n![Alt text](/path/to/img.jpg \"Optional Title\")\n```\n\n##### Image Reference\n\n```\nThis is ![an example][id] reference-style image descriptor.\n\n[id]: http://example.com/  \"Optional Title Here\"\n```\n\nnote: reference links require the `:reference-links?` option to be set to true\n\n\n### Image Link\n```\n[![Continuous Integration status](https://secure.travis-ci.org/yogthos/markdown-clj.png)](http://travis-ci.org/yogthos/markdown-clj)\n```\n\n### Table\n\nYou can create tables by assembling a list of words and dividing them with hyphens - (for the first row), and then separating each column with a pipe |:\n\n```\n| First Header  | Second Header |\n| ------------- | ------------- |\n| Content Cell  | Content Cell  |\n| Content Cell  | Content Cell  |\n```\n\nBy including colons : within the header row, you can define text to be left-aligned, right-aligned, or center-aligned:\n\n```\n| Left-Aligned  | Center Aligned    | Right Aligned |\n| :------------ | :---------------: | ------------: |\n| col 3 is      |  some wordy text  | $1600         |\n| col 2 is      |  centered         |   $12         |\n| zebra stripes |  are neat         |    $1         |\n```\n\nA colon on the left-most side indicates a left-aligned column; a colon on the right-most side indicates a right-aligned column; a colon on both sides indicates a center-aligned column.\n\n\n## Limitations\n\nThe parser reads the content line by line, this means that tag content is not allowed to span multiple lines.\n\n## License\n\nCopyright © 2015 Dmitri Sotnikov\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyogthos%2Fmarkdown-clj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyogthos%2Fmarkdown-clj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyogthos%2Fmarkdown-clj/lists"}