C#
.NET

ClearScriptとmarked.jsを使って.NETでGFMライクなMarkdownパーサーを手軽に作成する方法

More than 3 years have passed since last update.

.NETでMarkdownエディタを作る場合、HTMLに変換する部分にはMarkdownSharpやMarkdownDeepをNuGetで取得して使うのが一番手っ取り早いと思います。
ただ、これらのライブラリだとGitHub Flavored Markdown(GFM)の記法に対応しきれません。
特にバッククオートを使ったコード部分の記述には、先に挙げた二つは対応してないです。

JavaScript界隈ではGFMに対応したライブラリが結構あるなぁ、ということで、その中でもよさげなmarked.jsを.NETから使ってみようと思います。

ClearScriptとmarked.jsをNuGetで取得する

ClearScriptを使うと、JavaScriptのAPIを.NETからたたくことができます。
ClearScriptの概要についてはこちらの記事が詳しいです。

NuGetから、JavaScriptEngine.V8とmarked.jsを取得します。

PM> Install-Package JavaScriptEngineSwitcher.V8
PM> Install-Package marked

marked.jsはScriptsフォルダ以下に配置されます。
marked.jsのプロパティで、ビルドアクションを「埋め込まれたリソース」に変更します。

markedjsproperty.png

Markdownパーサーを実装する

public class MarkdownParser : IDisposable
{
    private IJsEngine _jsEngine;
    private bool _disposed;

    public MarkdownParser(IJsEngine jsEngine)
    {
        if (jsEngine == null) throw new ArgumentNullException("jsEngine");

        _jsEngine = jsEngine;
        _jsEngine.ExecuteResource("既定の名前空間.Scripts.marked.js", GetType());
    }

    public string Transform(string markdown)
    {
        return _jsEngine.CallFunction<string>("marked", markdown);
    }

    public void Dispose()
    {
        if (_disposed) return;
        _disposed = true;

        if (_jsEngine == null) return;
        _jsEngine.Dispose();
        _jsEngine = null;
    }
}

_jsEngine.ExecuteResource("既定の名前空間.Scripts.marked.js", GetType());

コンストラクタのこの部分で、JavaScriptエンジンにJavaScriptを読み込ませます。
埋め込まれたリソースへのパスは、プロジェクトの既定の名前空間+相対パスなので、適宜変更。

public string Transform(string markdown)
{
    return _jsEngine.CallFunction<string>("marked", markdown);
}

あとは、CallFunctionメソッドに、marked.jsの関数と、変換対象のMarkdownテキストを渡してあげるだけです。
パーサーの実装はこれだけ。

実行する

コンソールアプリで以下のようなコードを実行すると

class Program
{
    static void Main()
    {
        const string markdown = @"
    ```cs
    public class Foo
    {
        public string Bar { get; set; }

        public string Buz()
        {
            return Bar;
        }
    }
    ```
";

        var parser = new MarkdownParser(new V8JsEngine());

        var html = parser.Transform(markdown);

        Console.WriteLine(html);
        Console.ReadLine();
    }
}

markdownparserconsole.png

ちゃんとHTMLに変換されました。
※const string markdown以下の部分については、記事上で「```」をうまく表現できなかったので、前にスペースを設けてますが、コード上はスペースなしできちんと変換されます。

サンプルコード

GitHubhighlight.jsを使ってシンタックスハイライトも行うようなサンプルをあげてます。