6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PlantUMLからmermeidへの変換器を作ってみた

Last updated at Posted at 2022-02-23

モチベーション

最近GitHubが対応したことで一気に熱を帯びているmermeidだが、
PlantUMLからmermeidへの変換器が意外と落ちていなかった。
そこで、今回はPlantUMLからmermeidへの変換器を自作してみることにした。
(こちらの内容は自分のブログでも公開していますのでぜひご覧下さい。変換器はこちらでリリース予定です。)

言葉の説明

PlantUML

コードベースで作画ができるツール。古くから使われていて慣れ親しんでいる人も多いはず。
ER図、シーケンス図など, 様々な図の作成ができる。
PlantUML

mermeid

mermeidはpumlと同様、テキストベースで作図ができるライブラリである。
表現力はPlantUMLに比べ少し劣る印象ではあるものの、
javascript製のライブラリであるため、PlantUMLに比べ環境構築が容易で、web系のツールと親和性も良さそう。
(NotionやGithubが対応したのもそういった背景があるのかもしれない。)
mermeid

PlantUMLはかなり表現力のあるツールなので、今回はまずER図に絞って変換器を実装してみることにした。

両者の構文の比較

Entityの変換

Entityの書き方に対して、両者を比較してみる。
PlantUML

entity "Entity01" as e01 {
  *e1_id : number <<generated>>
  --
  *name : text
  description : text
}

mermeid

Entity01 {
  e1_id number
  name text
  description text
}

mermeidの場合、entityであることを宣言する必要がなく、カラムもタイプと命名の2つだけでかなりシンプルだ。
さらにentityに対して代替の命名ができないことも特徴(これがRelation変換部にも関わってくる。)

Relationの変換

Entityと同じく両者を比較してみる

PlantUML

e01 ||..o{ e02
e01 |o..o{ e03

mermeid

Entity01 ||--o{ Entity02 : places
Entity01 |o--o{ Entity03 : places

まず、mermeidにはentityに対して命名を割り当てる機構がないため
名付けが変わっている場合は元のものに置き換えなくてはならない。

またそれぞれのリレーションに対しては、説明を割り当てなくてはならない
(上記でいうところの"places"の部分)

さらに(細かな違いではあるが)リレーションに対して『..』は使えないようだ。
(PlantUMLの場合は破線が表現できる。)
こちらは使えるようです🙇‍♂️

その他

mermeidの場合、erDiagramという文を一番最初に入れ、ER図であることを明示的に宣言しなくてはいけないようである。
(PlantUMLに比べ文法が簡潔になっているのもこのためだろう。)

コード

完成したコードがこちら(今回はwebでの公開を意識してnodeで書いてみた)

const fs = require('fs')

const text = fs.readFileSync("puml.txt", 'utf8')
const lines = text.toString().split('\n')

let mermeid_text = 'erDiagram\n'

const entity_name_array = []
for (const line of lines) {
  
  if(line.includes('entity')){ // entity開始

    const entity_name = line.split(' ')[1].replace(/[\"]/g,"")

    if(line.includes('as')){ //entityに対して命名がなされている場合
        const entity_replaced_name = line.split('as')[1].replace('{',"").replaceAll(' ',"")
        entity_name_array.push([entity_name, entity_replaced_name])
    }

    mermeid_text += `${entity_name} {\n`

  } else if (line.includes(':')){ // カラム

      columns = line.split(':').map((column) => column.trim())
      column_text = ''
      if(columns.length == 1){
        column_text = `string ${columns[0].replace('*', '')}`
      }else{
        column_text = `${columns[0].replace('*', '')} ${columns[1].split(' ')[0]}`
      }

      mermeid_text += `  ${column_text}\n`

  } else if(line == '}'){ //entity終了

    mermeid_text += '}\n'

  } else if (line.includes('--') && line.length <= 4){
    
    // 不要なので無視

  } else if (line.match(new RegExp('[o|}]{0,2}(..|--)[o|{]{0,2}')) != null) { //relation
    new_relation = `${line.replace('..', '--')} : places\n`
    entity_name_array.forEach((entity_name_el) => {
      new_relation = new_relation.replace(entity_name_el[1], entity_name_el[0])
    })
    mermeid_text += new_relation
  } else {
    mermeid_text += `${line.replace('..', '--')}\n`
  }
}

// 書き込み
fs.writeFile("mermeid.txt", mermeid_text, (err) => {
    if (err) throw err
    console.log('正常に書き込みが完了しました')
});

今後やろうとしていること

package文への対応

PlantUMLのER図ではpackageの作成ができるが、mermeidは未対応のよう。
したがってPlantUMLにpackageに関する文があった場合、それを取り除く必要がある。
が、ここまでくると1行ごとの文解析では間に合わないので、良い解析の仕方がないかを模索中。

webでの公開

上記の通りmermeidはwebとの親和性が高い。
せっかくなので、puml to mermeidの変換器をwebで公開してみようと思う。

ER図以外への対応

こちらも上述の通り、PlantUMLは ER図以外にもシーケンス図など様々な図をサポートしている。
余裕があればこれらの図に関しても変換器を作ってみたい。

6
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?