Skip to content

loopwerk/Parsley

Repository files navigation

tag-changelog

A Markdown parser for Swift Package Manager, using Github Flavored Markdown. As such it comes with a bunch of Markdown extensions such as fenced code blocks, tables, strikethrough, hard line breaks and auto links.

Additionally Parsley supports embedded metadata in Markdown documents, and it splits the document title out from the document body.

let input = """
---
author: Kevin
tags: Swift, Parsley
---

# Hello World
This is the body
"""

let document = try Parsley.parse(input)
print(document.title) // Hello World
print(document.body) // <p>This is the body</p>
print(document.metadata) // ["author": "Kevin", "tags": "Swift, Parsley"]

Install

Parsley is available via Swift Package Manager and runs on macOS and Linux.

.package(url: "https://github.com/loopwerk/Parsley", from: "0.5.0"),

Use as a reader in Saga

Parsley can be used as a reader in the static site generator Saga, using SagaParsleyMarkdownReader.

Markdown attributes

Parsley supports adding attributes to Markdown elements using curly braces {...} with the following shorthand notations:

Notation HTML result
.myclass class="myclass"
#myid id="myid"
key="value" key="value"

Multiple classes are merged: {.foo .bar} becomes class="foo bar".

Attributes on code blocks are always enabled. For headings, images, and other block-level elements, you need to opt in with the .markdownAttributes option:

let html = try Parsley.html(input, options: [.markdownAttributes])
let document = try Parsley.parse(input, options: [.markdownAttributes])

Code blocks

Attributes are placed after the language on the opening fence line:

```python {.highlight data-title="views.py"}
def hello():
    print("Hello, World!")
```
<pre class="highlight" data-title="views.py"><code class="language-python">def hello():
    print("Hello, World!")
</code></pre>

As a shorthand, a title can also be specified without curly braces:

```python title="views.py"
def hello():
    print("Hello, World!")
```

This is equivalent to {data-title="views.py"} and generates:

<pre data-title="views.py"><code class="language-python">def hello():
    print("Hello, World!")
</code></pre>

You can then use CSS to display the title, for example:

pre[data-title]::before {
  content: attr(data-title);
  display: block;
  background: #1a1a1a;
  padding: 0.5em 1em;
  font-size: 0.85em;
  border-bottom: 1px solid #333;
}

Headings

Attributes are placed at the end of the heading line:

## My heading {.special #intro}
<h2 class="special" id="intro">My heading</h2>

Block elements

For paragraphs, blockquotes, lists, horizontal rules, and tables, place the attributes on their own line directly after the element:

This is a paragraph.
{.note}

> A blockquote.
{.warning}

* First
* Second
{.checklist}

---
{.divider}
<p class="note">This is a paragraph.</p>
<blockquote class="warning">
<p>A blockquote.</p>
</blockquote>
<ul class="checklist">
<li>First</li>
<li>Second</li>
</ul>
<hr class="divider" />

Standalone images

When an image is the only content in a paragraph, attributes are applied directly to the <img> element:

![Alt text](image.png)
{.hero}
<p><img src="image.png" alt="Alt text" class="hero" /></p>

Modifying the generated HTML

Parsley doesn't come with a plugin system, it relies purely on cmark-gfm under the hood to render Markdown to HTML. If you want to modify the generated HTML, for example if you want to add target="blank" to all external links, SwiftSoup is a great way to achieve this.

Code block syntax highlighting

If you want to add syntax highlighting to the code blocks, you could use a client-side JavaScript library such as Prism or highlight.js. Or for a server-side solution, check out Moon, which runs Prism in Swift:

import Parsley
import Moon

let html = try Parsley.html(markdown)
let highlighted = Moon.shared.highlightCodeBlocks(in: html)

Sponsor this project

  •  

Contributors

Languages