Home About Contact
Kotlin , Spring Boot , Markdown

mdtohtml を Spring Boot でつくる

本当は https://github.com/gomarkdown/mdtohtmlを使えばよいだけの話なのだが、 go をインストールしていないマシンで JavaVM はインストール済みだったので、 https://github.com/JetBrains/markdown と Spring Boot をつかって mdtohtml と(だいたい)同じように機能するコマンドラインツールをつくった。その備忘録です。

そういえば、過去のエントリー goldmark を使って markdown を HTMLに変換する mymark コマンドをつくった でも同じようなことしてたな。これは go 言語だが。 go がインストールされているならば結局この mdtohtml https://github.com/gomarkdown/mdtohtml を使えばよいだけではある。

作動環境

$ java --version
openjdk 17.0.11 2024-04-16
OpenJDK Runtime Environment (build 17.0.11+9-Ubuntu-122.04.1)
OpenJDK 64-Bit Server VM (build 17.0.11+9-Ubuntu-122.04.1, mixed mode, sharing)

コマンドラインアプリをつくる

spring initializr https://start.spring.io/ にて、プロジェクトのベースを設定してダウンロードする。

今回はこのようにしました。

spring-boot-initializr

GENERATE ボタンをクリックするとローカルに mdtohtml.zip がダウンロードされるので、 これを適当なディレクトリで unzip します。

cd mdtohtml でプロジェクトのホームディレクトリに移動して、 事前に用意された MdtohtmlApplication.kt を確認。

$ cat src/main/kotlin/com/mindboardapps/tool/mdtohtml/MdtohtmlApplication.kt
package com.mindboardapps.tool.mdtohtml

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class MdtohtmlApplication

fun main(args: Array<String>) {
        runApplication<MdtohtmlApplication>(*args)
}

これの main 部分を次のように書きかえる。

fun main(args: Array<String>) {
    runApplication<MdtohtmlApplication>(*args){
        println("Hello")
    }
}    

そして、bootRun する。

$ ./gradlew bootRun

> Task :bootRun
Hello

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.2)

作動した。

まず、Spring のロゴが出るやつを消す。

src/main/resources/application.properties を編集。

spring.application.name=mdtohtml
spring.main.banner-mode=off
logging.level.root=OFF

再度 bootRun する。

$ ./gradlew bootRun

> Task :bootRun
Hello

BUILD SUCCESSFUL in 2s
5 actionable tasks: 4 executed, 1 up-to-date

ロゴ消えました。

それでは肝心のmd to html 変換のコードを書きます。

https://github.com/JetBrains/markdownを使うので、その依存を build.gradle に追記。

dependencies {
    ...
    implementation("org.jetbrains:markdown:0.7.3")
    ...
}

バージョンは現時点で 0.7.3 が最新だったようなのでそれを指定。

変換コードを 上記Githubのページから MdtohtmlApplication.kt の main 関数にコピペ。

import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
import org.intellij.markdown.parser.MarkdownParser
import org.intellij.markdown.html.HtmlGenerator

...

fun main(args: Array<String>) {
    runApplication<MdtohtmlApplication>(*args){
        //println("Hello")
        val src = "Some *Markdown*"
        val flavour = CommonMarkFlavourDescriptor()
        val parsedTree = MarkdownParser(flavour).buildMarkdownTreeFromString(src)
        val html = HtmlGenerator(src, parsedTree, flavour).generateHtml()
        println(html)

これで実行してみます。

$ ./gradlew bootRun

> Task :bootRun
<body><p>Some <em>Markdown</em></p></body>

できました。

あとは、src の部分に自分が変換させたいマークダウンテキストが入るようにすればよい。

ここでは 次のようにコマンドラインから変換元ファイル(md) と変換先ファイル(html)を指定して使いたい。

$ java -jar mdtohtml.jar foo.md foo.html

そこで、 MdtohtmlApplication.kt は次のようにしました。

fun main(args: Array<String>) {
    runApplication<MdtohtmlApplication>(*args){
        if( args.size>1 ){
            val mdFile = File(args[0])
            val htmlFile = File(args[1])
            if( mdFile.exists() ){
                val src = mdFile.text
                val flavour = CommonMarkFlavourDescriptor()
                val parsedTree = MarkdownParser(flavour).buildMarkdownTreeFromString(src)
                val html = HtmlGenerator(src, parsedTree, flavour).generateHtml()
                htmlFile.text = html
            }
        }
    }
}

file.text でテキストファイルを読み書きできるように拡張関数のコードを入れます。

import java.io.File

object FileUtils {
    val writeText: (File, String)->Unit = {file, content->
        file.writeText(content, Charsets.UTF_8)
    }
    val readText: (File)->String = {file->
        file.readText(Charsets.UTF_8)
    }
}

var File.text: String
     get() = FileUtils.readText(this)
     set(v) = FileUtils.writeText(this, v)

詳しくは こちらのエントリーを参照: Groovy のようにテキストを読み書きする

./gradlew bootJar して 実行できる jar を生成します。

$ ./gradlew bootJar

BUILD SUCCESSFUL in 1s
5 actionable tasks: 1 executed, 4 up-to-date

そして、foo.md を foo.html に変換。

$ echo "Some *Markdown*" > foo.md
$ java -jar build/libs/mdtohtml-0.0.1-SNAPSHOT.jar foo.md foo.html
$ cat foo.html 
<body><p>Some <em>Markdown</em></p></body>

これで完成です。

追伸

mdtohtml コマンドとして使えるように mdtohtml ファイルを設置。

~/.local/mdtohtml/bin/mdtohtml

#!/bin/bash
d=$(cd $(dirname $0); pwd)
java -jar $d/mdtohtml-0.0.1-SNAPSHOT.jar $1 $2

mdtohtml コマンドと同じディレクトリに mdtohtml-0.0.1-SNAPSHOT.jar を配置しておきます。

u+x して実行権を付与します。

$ cd ~/.local/mdtohtml/bin
$ chmod u+x ./mdtohtml

あとは、 ~/.bashrc などで ~/.local/mdtohtml/bin にパスを通して完了です。