
マークダウンのmetadata(yaml header)をNode.jsでパースする
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部 Delivery部の若槻です。
マークダウン(Markdown)文書では、次のようにファイルの冒頭で---を使ってmetadata(yaml header)を定義することができます。
--- title: This is a test description: Once upon a time... --- # Title of my great post Lorem ipsum dolor...
レンダリング側がサポートしているかに依りますが、VS Codeのマークダウンプレビュー機能であれば、ソース側で記述されていたmetadataをプレビュー側ではちゃんと消してくれます。

逆にGitHubではテーブル形式で表示してくれます。

今回は、このマークダウンのmetadataをNode.jsでパースする方法を確認してみました。
方法
npmパッケージのparse-mdが良さそうだったので使ってみます。
インストール
npm i parse-md
コード
import fs from 'fs'
import parseMD from 'parse-md'
const fileContents = fs.readFileSync('posts/first.md', 'utf8');
const { metadata, content } = parseMD(fileContents);
console.log(metadata);
console.log(content);
実行するとmetadataおよびcontentをパースできました。
$ node parse.js
{ title: 'This is a test', description: 'Once upon a time...' }
# Title of my great post
Lorem ipsum dolor...
実行がnode:65885エラーとなる場合
$ node parse.js
(node:65885) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/parse.js:1
import fs from 'fs'
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1033:15)
at Module._compile (node:internal/modules/cjs/loader:1069:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47
package.jsonに次の記述を追加して、パッケージ内の全ての.jsファイルがcommonjsではなくESモジュールとして扱われるようにします。
{
"type": "module"
}
TypeScriptで書くなら
TypeScriptで書く場合は次のようになりました。
import * as fs from 'fs';
import parseMD from './node_modules/parse-md/dist/index.js';
const fileContents = fs.readFileSync('posts/first.md', 'utf8');
const { metadata, content } = parseMD(fileContents);
console.log(metadata);
console.log(content);
ちなみにインポートをimport parseMD from 'parse-md'としたら、parse-mdの定義ファイルが無いよと怒られます。

Could not find a declaration file for module 'parse-md'. '/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/parse-md.js' implicitly has an 'any' type.
JavaScriptの時と同じですが、package.jsonに次の記述を追加して、パッケージ内の全ての.jsファイルがcommonjsではなくESモジュールとして扱われるようにします。
{
"type": "module"
}
tsconfig.jsonの記述を次のようにします。compilerOptions.moduleでesnextまたはes2020を指定してモジュールをESモジュールとして読み込むようにします。また"ts-node": {"esm": true}を追加してERR_UNKNOWN_FILE_EXTENSIONを回避します。(ts-node-esmまたはts-node --esmでも回避できます。)
{
"compilerOptions": {
"module": "esnext",
},
"ts-node": {
"esm": true
}
}
実行できました。
$ npx ts-node parse.ts
{ title: 'This is a test', description: 'Once upon a time...' }
# Title of my great post
Lorem ipsum dolor...
参考
以上






