otaviocc / MarkdownDSL

Simple Markdown DSL in Swift using Result Builders and Callable Types.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Markdown

This Swift Package implements a Markdown DSL in Swift, using Result Builders and Callable Types.

let markdown = document {
    section("Section") {
        paragraph {
            "This is a sentence."
            "And this is another sentence."
        }
    }

    section("Another Section") {
        section("Subsection") {
            quote {
                "This is a quote in italic."
                    .textStyle(.italic)
            }

            paragraph {
                "While the example below is a code block:"
            }

            code("swift") {
                #"""
                print("hello world!")
                """#
            }
        }
    }
}

Sections

Sections are one of the most important features in a Markdown file. When writing a Markdown file it's quite easy to misuse #, ##, etc... without thinking of the document hierarchy. This DSL simplifies it by removing from the syntax the section level. Sections are automatically set based on the level they are in the document. Nesting sections creates subsections.

The example below

section("Title") {
    // ...
}

results in

# Title

while nested sections

section("Title") {
    section("Subtitle") {
        // ...
    }
}

result in

# Title
## Subtitle

Paragraphs

Paragraphs are sequences of sentences. The example below

paragraph {
    "This is a sentence."
    "This is another sentence."
}

results in

This is a sentence. This is another sentence.

Lists

Another important element in a Markdown is a list. The example below shows a simple list

list {
    "This is an item"
    "This is another item"
}

which, when rendered, results in

* This is an item
* This is another item

Quote

quote {
    "This is something someone said."
}

results in

> This is something someone said.

Code

Code blocks take an additional parameter used to specify the programming language used in the block

code("swift") {
    #"""
    func yTown() -> String { "Berlin" }
    """#
}

results in

```swift
func yTown() -> String { "Berlin" }
```

Text modifiers

Markdown supports bold and italic texts. These can be set using the textStyle(:) modifier.

"bold text"
    .textStyle(.bold)

results in

**bold text**

while

"italic text"
    .textStyle(.italic)

results in

*italic text*

Links

Links are also set via text modifier:

"this link"
    .link("https://github.com")

results in

[this link]("https://github.com")

Combining modifiers

Modifiers can be combined to achieve the desired behavior

"this is a bold link"
    .textStyle(.bold)
    .link("https://github.com")

results in

[**this is a bold link**]("https://github.com")

Conditionals

Conditionals can be used to decide which Markdown element to display.

document {
    if showShowCode {
        code("swift") {
            #"""
            func yTown() -> String { "Berlin" }
            """#
        }
    } else {
        paragraph {
            "let's omit the code example instead"
        }
    }
}

Loops

For loops can be used to set a sequence of strings or Markdown elements:

document {
    for value in (0..<5) {
        paragraph {
            "Paragraph \(value)."
        }
    }

     paragraph {
        for value in (0..<5) {
            "Sentence \(value)."
        }
    }
}

Additional examples

The implementation is covered by Unit Tests, which provide additional examples on how to use and what to expect from this Swift Package.

Recommendation

This Package isn't supposed to be used in production. This is a simple experiment on how to use Result Builders and Callable Types. I don't have plans to maintain it, but contributions are welcomed.

About

Simple Markdown DSL in Swift using Result Builders and Callable Types.


Languages

Language:Swift 100.0%