Typesafe Config(HOCON)のコードブロックにPrism.jsでシンタックスハイライトを当てる
Prism.jsはコードブロックにシンタックスハイライトを当てる便利なライブラリです。
Typesafe Configをハイライトする機能はサポートされていませんが、独自にルールを定義することによってシンタックスハイライトを適用することができます。
Typesafe Config とは?
https://github.com/lightbend/config
ScalaやJavaで使えるconfigライブラリです。
PlayFrameworkのプロジェクトでよく使います。
一般的には、HOCON(Human-Optimized Config Object Notation)形式で書かれます。
ハイライトする
冒頭で書いたように、Typesafe Configはサポートされていないのでハイライトルールを独自に定義します。
(issueは出ていました。)
ハイライトルール(Grammar)
Prism.jsはハイライトルールを正規表現で定義します。
JSONを参考にHOCON用に拡張してみました。
全てのパターンで完璧にハイライトできるわけではありませんが、基本は問題なく動くと思います。
JavaScript
const hoconGrammar = {
property: [/(?:[\w\-]|[^:\/\+.\[\]{}="$\s\r\n]+)/, /"(?:\\.|[^"\r\n]*)"/].map(
r => ({
pattern: new RegExp(r.source + '(?=\\s*(?:[\\.:={]|\\+=))'),
lookbehind: true,
greedy: true,
}),
),
string: [
{ pattern: /"""[\s\S]*?"""/, greedy: true },
{
pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,
lookbehind: true,
greedy: true,
},
],
comment: { pattern: /(\/\/|#).*/, greedy: true },
punctuation: /[\${}\[\],]/,
operator: /[:=]/,
keyword: {
pattern: /(?:^|\s)include(?=\s)/,
lookbehind: true,
greedy: true,
},
function: {
pattern: /(?:^|\s)(file|url|classpath|required)(?=\()/,
greedy: true,
},
}
Node.jsで使う例
Node.js
import Prism from 'prismjs'
const code = 'key = "value"'
const result = Prism.highlight(code, hoconGrammar, 'hocon')
console.log(result)
結果
<span class="token property">key</span> <span class="token operator">=</span> <span class="token string">"value"</span>
HTMLで使う例
HTML
<pre><code class="language-hocon">
key = "value"
</code></pre>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/prism.min.js"></script>
<script>
Prism.languages.hocon = {
// 省略
// hoconGrammarをここに書く
}
</script>
Prism.languagesを拡張してhoconを追加、codeタグのclassにlanguage-hoconを追加するとハイライトできます。
コードサンプル: https://github.com/murosan/prism-test/blob/main/docs/hocon.html
実際にハイライトした例: https://murosan.github.io/prism-test/hocon.html
サンプル
Typesafe
// コメント
# コメント
not.a.comment = [
"文字列の中はコメントではない"
"//quoted",
"#string"
]//comment
arr=[1,2 3]
"fo:o": { "a" : 42 },
"f$oo" : [null, true, false],
"foo " : { "b" : 43 }
"foo" : { "a" : 42, "b" : 1e5 }
// a b c は有効なプロパティだけど、このGrammarだとハイライトされない..
// こういう書き方は普通しないので問題ないと思うが..
a b c : 42
"a b c" : 43
without_colon { a: 100 } // {が続く場合は:や=なしでも良い
obj = {
aaa.bbb = 100
ccc.ddd = [200 300]
eee.fff {
ggg.hhh: xxxx
}
}
// Scalaのmultiline stringsみたいなやつが使える
multiline = """"
" aaa
bbb
"""
// プロパティにもできる
"""
multilinekey
""": val
data-center-generic = { cluster-size = 6 }
data-center-east = ${data-center-generic} { name = "ea:st" }
path = [ /bin ]
path = ${?path} [ /usr/bin ]
path += /usr/local/bin
path -= /usr/sbin // "path -" is a valid key
included {
include
"another.conf"
}
;;;|||¥¥¥--- = ok
include file("aaa.conf")
include url("file://bbb.conf")
include classpath("ccc.conf")
include required("ddd.conf")