Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use markd for markdown rendering in the compiler #11040

Merged
merged 3 commits into from Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 34 additions & 0 deletions lib/markd/.github/workflows/linux-ci.yml
@@ -0,0 +1,34 @@
name: Linux CI
on:
push:
paths-ignore:
- "benchmarks/**"
branches:
- "master"
pull_request:
branches: "*"

jobs:
specs:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
crystal: [ '1.0.0', 'latest', 'nightly' ]
name: Crystal ${{ matrix.crystal }} tests
steps:
- uses: actions/checkout@master
- uses: oprypin/install-crystal@v1
with:
crystal: ${{ matrix.crystal }}
- name: Install dependencies
run: shards install
- name: Run tests
run: crystal spec --error-on-warnings --error-trace
- name: Run code format check
run: |
if ! crystal tool format --check; then
crystal tool format
git diff
exit 1
fi
22 changes: 22 additions & 0 deletions lib/markd/.github/workflows/release-version.yml
@@ -0,0 +1,22 @@
name: Deploy new release
on:
push:
tags:
- "v*"

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false

12 changes: 12 additions & 0 deletions lib/markd/.gitignore
@@ -0,0 +1,12 @@
/doc/
/lib/
/bin/
/.shards/
/src/main.cr

# Libraries don't need dependency lock
# Dependencies will be locked in application that uses them
/shard.lock

# vscode
/.history/
13 changes: 13 additions & 0 deletions lib/markd/.vscode/launch.json
@@ -0,0 +1,13 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Launch",
"program": "${workspaceRoot}/bin/main",
"args": [],
"cwd": "${workspaceRoot}"
}
]
}
61 changes: 61 additions & 0 deletions lib/markd/CHANGELOG.md
@@ -0,0 +1,61 @@
# Change Log

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

### TODO

- GFM support

## [0.4.0] (2021-03-23)

- Compatibility with Crystal 1.0. #[34](https://github.com/icyleaf/markd/pull/34) thanks @[bcardiff](https://github.com/bcardiff).

## [0.3.0] (2021-03-02)

No changelog.

## [0.2.1] (2020-08-24)

### Added

- Add Options#base_url to allow resolving relative links. #[26](https://github.com/icyleaf/markd/pull/26), #[28](https://github.com/icyleaf/markd/pull/28) thanks @[straight-shoota](https://github.com/straight-shoota).

### Fixed

- [high severity] escape unsafe html entry inline of code block. #[32](https://github.com/icyleaf/markd/pull/32).
- Fixed some typos in README. #[29](https://github.com/icyleaf/markd/pull/29) thanks @[Calamari](https://github.com/Calamari).

## [0.2.0] (2019-10-08)

### Changed

- Optimizations speed. many thanks @[asterite](https://github.com/asterite). #[19](https://github.com/icyleaf/markd/pull/19)

### Fixed

- Compatibility with Crystal 0.31. #[22](https://github.com/icyleaf/markd/pull/22).

## [0.1.2] (2019-08-26)

- Use Crystal v0.31.0 as default complier.

## [0.1.1] (2017-12-26)

- Minor refactoring and improving speed. thanks @[straight-shoota](https://github.com/straight-shoota).
- Use Crystal v0.24.1 as default complier.

## 0.1.0 (2017-09-22)

- [initial implementation](https://github.com/icyleaf/markd/milestone/1?closed=1)

[Unreleased]: https://github.com/icyleaf/markd/compare/v0.3.0...HEAD
[0.3.0]: https://github.com/icyleaf/halite/compare/v0.2.1...v0.3.0
[0.2.1]: https://github.com/icyleaf/halite/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/icyleaf/halite/compare/v0.1.2...v0.2.0
[0.1.2]: https://github.com/icyleaf/halite/compare/v0.1.1...v0.1.2
[0.1.1]: https://github.com/icyleaf/halite/compare/v0.1.0...v0.1.1
21 changes: 21 additions & 0 deletions lib/markd/LICENSE
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2017-present icyleaf

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
111 changes: 111 additions & 0 deletions lib/markd/README.md
@@ -0,0 +1,111 @@
# markd

[![Language](https://img.shields.io/badge/language-crystal-776791.svg)](https://github.com/crystal-lang/crystal)
[![Tag](https://img.shields.io/github/tag/icyleaf/markd.svg)](https://github.com/icyleaf/markd/blob/master/CHANGELOG.md)
[![Build Status](https://img.shields.io/circleci/project/github/icyleaf/markd/master.svg?style=flat)](https://circleci.com/gh/icyleaf/markd)

Yet another markdown parser built for speed, written in [Crystal](https://crystal-lang.org), Compliant to [CommonMark](http://spec.commonmark.org) specification (`v0.27`). Copy from [commonmark.js](https://github.com/jgm/commonmark.js).

## Installation

Add this to your application's `shard.yml`:

```yaml
dependencies:
markd:
github: icyleaf/markd
```

## Quick start

```crystal
require "markd"

markdown = <<-MD
# Hello Markd

> Yet another markdown parser built for speed, written in Crystal, Compliant to CommonMark specification.
MD

html = Markd.to_html(markdown)
```

Also here are options to configure the parse and render.

```crystal
options = Markd::Options.new(smart: true, safe: true)
Markd.to_html(markdown, options)
```

## Options

| Name | Type | Default value | Description |
| ----------- | ------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| time | `Bool` | false | render parse cost time during read source, parse blocks, parse inline. |
| smart | `Bool` | false | if **true**, straight quotes will be made curly,<br />`--` will be changed to an en dash,<br />`---` will be changed to an em dash, and<br />`...` will be changed to ellipses. |
| source_pos | `Bool` | false | if **true**, source position information for block-level elements<br />will be rendered in the data-sourcepos attribute (for HTML) |
| safe | `Bool` | false | if **true**, raw HTML will not be passed through to HTML output (it will be replaced by comments) |
| prettyprint | `Bool` | false | if **true**, code tags generated by code blocks will have a `prettyprint` class added to them, to be used by [Google code-prettify](https://github.com/google/code-prettify). |
| gfm | `Bool` | false | **Not supported for now** |
| toc | `Bool` | false | **Not supported for now** |
| base_url | `URI?` | nil | if not **nil**, relative URLs of links are resolved against this `URI`. It act's like HTML's `<base href="base_url">` in the context of a Markdown document. |

## Advanced

If you want to use a custom renderer, it can!

```crystal

class CustomRenderer < Markd::Renderer

def strong(node, entering)
end

# more methods following in render.
end

options = Markd::Options.new(time: true)
document = Markd::Parser.parse(markdown, options)
renderer = CustomRenderer.new(options)

html = renderer.render(document)
```

## Performance

First of all, Markd is slower than [Crystal Built-in Markdown](https://crystal-lang.org/api/0.23.0/Markdown.html) which it is a lite version, only apply for generte Cystal documents ([#4496](https://github.com/crystal-lang/crystal/pull/4496), [#4613](https://github.com/crystal-lang/crystal/issues/4613)).

Here is the result of [a sample markdown file](benchmarks/source.md) parse at MacBook Pro Retina 2015 (2.2 GHz):

```
Crystal Markdown 3.28k (305.29µs) (± 0.92%) fastest
Markd 305.36 ( 3.27ms) (± 5.52%) 10.73× slower
```

Recently, I'm working to compare the other popular commonmark parser, the code is stored in [benchmarks](/benchmarks).

## Donate

Markd is an open source, collaboratively funded project. If you run a business and are using Markd in a revenue-generating product,
it would make business sense to sponsor Markd development. Individual users are also welcome to make a one time donation
if Markd has helped you in your work or personal projects.

You can donate via [Paypal](https://www.paypal.me/icyleaf/5).

## How to Contribute

Your contributions are always welcome! Please submit a pull request or create an issue to add a new question, bug or feature to the list.

All [Contributors](https://github.com/icyleaf/markd/graphs/contributors) are on the wall.

## You may also like

- [halite](https://github.com/icyleaf/halite) - HTTP Requests Client with a chainable REST API, built-in sessions and middlewares.
- [totem](https://github.com/icyleaf/totem) - Load and parse a configuration file or string in JSON, YAML, dotenv formats.
- [poncho](https://github.com/icyleaf/poncho) - A .env parser/loader improved for performance.
- [popcorn](https://github.com/icyleaf/popcorn) - Easy and Safe casting from one type to another.
- [fast-crystal](https://github.com/icyleaf/fast-crystal) - 💨 Writing Fast Crystal 😍 -- Collect Common Crystal idioms.

## License

[MIT License](https://github.com/icyleaf/markd/blob/master/LICENSE) © icyleaf
9 changes: 9 additions & 0 deletions lib/markd/shard.yml
@@ -0,0 +1,9 @@
name: markd
version: 0.4.0

authors:
- icyleaf <icyleaf.cn@gmail.com>

crystal: 1.0.0

license: MIT
21 changes: 21 additions & 0 deletions lib/markd/spec/api_spec.cr
@@ -0,0 +1,21 @@
require "spec"
require "../src/markd"

describe Markd::Options do
describe "#base_url" do
it "it disabled by default" do
options = Markd::Options.new
Markd.to_html("[foo](bar)", options).should eq %(<p><a href="bar">foo</a></p>\n)
Markd.to_html("![](bar)", options).should eq %(<p><img src="bar" alt="" /></p>\n)
end

it "absolutizes relative urls" do
options = Markd::Options.new
options.base_url = URI.parse("http://example.com")
Markd.to_html("[foo](bar)", options).should eq %(<p><a href="http://example.com/bar">foo</a></p>\n)
Markd.to_html("[foo](https://example.com/baz)", options).should eq %(<p><a href="https://example.com/baz">foo</a></p>\n)
Markd.to_html("![](bar)", options).should eq %(<p><img src="http://example.com/bar" alt="" /></p>\n)
Markd.to_html("![](https://example.com/baz)", options).should eq %(<p><img src="https://example.com/baz" alt="" /></p>\n)
end
end
end
81 changes: 81 additions & 0 deletions lib/markd/spec/fixtures/regression.txt
@@ -0,0 +1,81 @@
# Regression tests

Eating a character after a partially consumed tab.

```````````````````````````````` example
* foo
→bar
.
<ul>
<li>foo
bar</li>
</ul>
````````````````````````````````

Type 7 HTML block followed by whitespace (#98).

```````````````````````````````` example
<a>
x
.
<a>
x
````````````````````````````````

h2..h6 raw HTML blocks (jgm/CommonMark#430).

```````````````````````````````` example
<h1>lorem</h1>

<h2>lorem</h2>

<h3>lorem</h3>

<h4>lorem</h4>

<h5>lorem</h5>

<h6>lorem</h6>
.
<h1>lorem</h1>
<h2>lorem</h2>
<h3>lorem</h3>
<h4>lorem</h4>
<h5>lorem</h5>
<h6>lorem</h6>
````````````````````````````````

Issue #109 - tabs after setext header line


```````````````````````````````` example
hi
--→
.
<h2>hi</h2>
````````````````````````````````

Issue #108 - Chinese punctuation not recognized

```````````````````````````````` example
**。**话
.
<p>**。**话</p>
````````````````````````````````

Issue jgm/cmark#177 - incorrect emphasis parsing

```````````````````````````````` example
a***b* c*
.
<p>a*<em><em>b</em> c</em></p>
````````````````````````````````

Issue jgm/CommonMark#468 - backslash at end of link definition


```````````````````````````````` example
[\]: test
.
<p>[]: test</p>
````````````````````````````````