マークダウンのmetadata(yaml header)をNode.jsでパースする
こんにちは、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...
参考
以上