MarkdownをHTMLに変換する
前のセクションではコマンドライン引数で受け取ったファイルを読み込み、標準出力に表示しました。 次は読み込んだMarkdownファイルをHTMLに変換して、その結果を標準出力に表示してみましょう。
markedパッケージを使う
JavaScriptでMarkdownをHTMLへ変換するために、今回はmarkedというライブラリを使用します。
markedのパッケージはnpmで配布されているので、commanderと同様にnpm install
コマンドでパッケージをインストールしましょう。
$ npm install marked@4.0
インストールが完了したら、Node.jsのスクリプトから読み込みます。
前のセクションの最後で書いたスクリプトに、marked
モジュールの読み込み処理を追加しましょう。
次のようにmain.js
を変更し、読み込んだMarkdownファイルをmarkedを使ってHTMLに変換します。
marked
モジュールからインポートしたmarked.parse
関数は、Markdown文字列を引数にとり、HTML文字列に変換して返します。
main.js
import { program } from "commander";
import * as fs from "node:fs/promises";
// markedモジュールからmarkedオブジェクトをインポートする
import { marked } from "marked";
program.parse(process.argv);
const filePath = program.args[0];
fs.readFile(filePath, { encoding: "utf8" }).then(file => {
// MarkdownファイルをHTML文字列に変換する
const html = marked.parse(file);
console.log(html);
}).catch(err => {
console.error(err.message);
process.exit(1);
});
変換オプションを作成する
markedにはMarkdownの変換オプションがあり、オプションの設定によって変換後のHTMLが変化します。 そこで、アプリケーション中でオプションのデフォルト値を決め、さらにコマンドライン引数から設定を切り替えられるようにしてみましょう。
今回のアプリケーションでは、例としてgfm
というmarkedのオプションを扱います。
gfmオプション
gfm
オプションは、GitHubにおけるMarkdownの仕様(GitHub Flavored Markdown, GFM)に合わせて変換するかを決めるオプションです。
markedではこのgfm
オプションがデフォルトでtrue
になっています。GFMは標準的なMarkdownにいくつかの拡張を加えたもので、代表的な拡張がURLの自動リンク化です。
次のようにsample.md
を変更し、先ほどのスクリプトとgfm
オプションをfalse
にしたスクリプトで結果の違いを見てみましょう。
sample.md
# サンプルファイル
これはサンプルです。
https://jsprimer.net/
- サンプル1
- サンプル2
gfm
オプションが有効のときは、URLの文字列が自動的に<a>
タグのリンクに置き換わります。
<h1 id="サンプルファイル">サンプルファイル</h1>
<p>これはサンプルです。
<a href="https://jsprimer.net/">https://jsprimer.net/</a></p>
<ul>
<li>サンプル1</li>
<li>サンプル2</li>
</ul>
一方、次のようにgfm
オプションをfalse
にすると、単なる文字列として扱われ、リンクには置き換わりません。
main.js
import { program } from "commander";
import * as fs from "node:fs/promises";
import { marked } from "marked";
program.parse(process.argv);
const filePath = program.args[0];
fs.readFile(filePath, { encoding: "utf8" }).then(file => {
// gfmオプションを無効にする
const html = marked.parse(file, {
gfm: false
});
console.log(html);
}).catch(err => {
console.error(err.message);
process.exit(1);
});
<h1 id="サンプルファイル">サンプルファイル</h1>
<p>これはサンプルです。
https://jsprimer.net/</p>
<ul>
<li>サンプル1</li>
<li>サンプル2</li>
</ul>
自動リンクのほかにもいくつかの拡張がありますが、詳しくはGitHub Flavored Markdownのドキュメントを参照してください。
コマンドライン引数からオプションを受け取る
次に、gfm
オプションをコマンドライン引数で制御できるようにしましょう。
アプリケーションのデフォルトではgfm
オプションを無効にした上で、次のように--gfm
オプションを付与してコマンドを実行できるようにします。
$ node main.js --gfm sample.md
コマンドライン引数で--gfm
のようなオプションを扱いたいときには、commanderのoption
メソッドを使います。
次のように必要なオプションを定義してからコマンドライン引数をパースすると、program.opts
メソッドでパース結果のオブジェクトを取得できます。
// gfmオプションを定義する
program.option("--gfm", "GFMを有効にする");
// コマンドライン引数をパースする
program.parse(process.argv);
// オプションのパース結果をオブジェクトとして取得する
const options = program.opts();
console.log(options.gfm);
--gfm
オプションはファイルパスを指定するsample.md
の前後のどちらについていても動作します。
なぜならprogram.args
配列にはprogram.option
メソッドで定義したオプションが含まれないためです。
process.argv
配列を直接使っているとこのようなオプションの処理が面倒なので、commanderのようなパース処理を挟むのが一般的です。
デフォルト設定を定義する
アプリケーション側でデフォルト設定を持っておくことで、将来的にmarkedの挙動が変わったときにも影響を受けにくくなります。
次のようにオプションを表現したcliOptions
オブジェクトを作成し、program.opts
メソッドの返り値から取得した値をセットします。
コマンドライン引数で指定されなかったオプションには??
(Nullish coalescing演算子)を使ってデフォルトの値をセットします。
Nullish coalescing演算子は左辺がnullishであるときにだけ右辺の値を返すため、値が指定されなかった状態と明示的にfalse
が与えられた状態を区別したいときに便利です。
// コマンドライン引数のオプションを取得する
const options = program.opts();
// コマンドライン引数で指定されなかったオプションにデフォルト値を上書きする
const cliOptions = {
gfm: options.gfm ?? false,
};
こうして作成したcliOptionsオブジェクトを、markedのparse
関数へオプションとして渡しましょう。main.js
の全体は次のようになります。
main.js
import { program } from "commander";
import * as fs from "node:fs/promises";
import { marked } from "marked";
// gfmオプションを定義する
program.option("--gfm", "GFMを有効にする");
program.parse(process.argv);
const filePath = program.args[0];
// コマンドライン引数のオプションを取得する
const options = program.opts();
// コマンドライン引数で指定されなかったオプションにデフォルト値を上書きする
const cliOptions = {
gfm: options.gfm ?? false,
};
fs.readFile(filePath, { encoding: "utf8" }).then(file => {
const html = marked.parse(file, {
// オプションの値を使用する
gfm: cliOptions.gfm,
});
console.log(html);
}).catch(err => {
console.error(err.message);
process.exit(1);
});
定義したコマンドライン引数を使って、Markdownファイルを変換してみましょう。
$ node main.js sample.md
<h1 id="サンプルファイル">サンプルファイル</h1>
<p>これはサンプルです。
https://jsprimer.net/</p>
<ul>
<li>サンプル1</li>
<li>サンプル2</li>
</ul>
また、gfm
オプションを付与して実行すると次のように出力されるはずです。
$ node main.js --gfm sample.md
<h1 id="サンプルファイル">サンプルファイル</h1>
<p>これはサンプルです。
<a href="https://jsprimer.net/">https://jsprimer.net/</a></p>
<ul>
<li>サンプル1</li>
<li>サンプル2</li>
</ul>
これでMarkdown変換の設定をコマンドライン引数でオプションとして与えられるようになりました。 次のセクションではアプリケーションのコードを整理し、最後にユニットテストを導入します。
このセクションのチェックリスト
- markedパッケージを使ってMarkdown文字列をHTML文字列に変換した
- コマンドライン引数でmarkedの変換オプションを設定した
- デフォルトオプションを定義し、コマンドライン引数で上書きできるようにした