sounisi5011/vec-draw

unist specによるAST生成を導入する

Closed this issue · 5 comments

概要

AST等の生成にunistを導入する。

詳細

開発中の #13 において、SVGを生成するために独自実装した仮想ノードを変換している。これを、驚くような大手のプロジェクトでも採用されているらしいunistを使用したものに切り替える。

メリット

  • デファクトスタンダード(?)な仕様に従うことで、有志のライブラリを再利用できる
  • 今後vec-drawのデベロッパーツール等を制作する際の助けになる
  • JSONと完全互換のツリー

デメリット

  • 学習コスト
  • ライブラリの複雑化
  • 開発に遅れが生じる

備考

unistに対応したHTMLを表現する仕様hastのツリーをhyperscripth()関数)形式で生成できるライブラリにhastscriptなるものが存在する。

知った経緯をメモしておこうか。

  1. PEGを書きやすくする拡張構文の調査(構文ルール編) - Qiita」を読んで、PEG.jsの機能不足さに危機感を抱く。
  2. PEG.js以外のPEGライブラリを探して「js peg」と検索
  3. PEG.js で機械的に構文を定義したい時に ejs 使ったら便利だった - カラクリスタ・ノート」という記事を発見
  4. 記事内にて言及されていた「HAST」なるものに興味を抱く。
  5. ようこそ、unifiedの世界へ。

unistの導入は、 #13 が一旦完了してからにしよう。基本的な文法に対応してから導入しても遅くはない。

使い方はこのようなものを想定。

import fs from 'fs';
import util from 'util';

import unified from 'unified';
import createStream from 'unified-stream';
import rehypeStringify from 'rehype-stringify';

import { parse, ast2rehype } from '@sounisi5011/vec-draw';

const readFileAsync = util.promisify(fs.readFile);
const writeFileAsync = util.promisify(fs.writeFile);

(async () => {
  const inputDSLText = await readFileAsync('input.vec-draw', 'utf-8');
  const outputSVGText = await unified()
    .use(parse)
    .use(ast2rehype)
    .use(rehypeStringify)
    .process(inputDSLText);
  await writeFileAsync('output.svg', outputSVGText);

  const processor = unified()
    .use(parse)
    .use(ast2rehype)
    .use(rehypeStringify);
  const src = fs.createReadStream('src.vec-draw', 'utf8');
  const dest = fs.createWriteStream('dest.svg', 'utf8');
  src.pipe(createStream(processor)).pipe(dest);
})();

parseは以下のような感じで定義。

export function parse(options) {
  this.Parser = file => {
    const fileText = String(file);
    const ast = /* fileTextをASTオブジェクトに変換する処理 */;
    return ast;
  };
}

#24 で作業を開始したのでこっちも再度open。

#24 が完了したので、closeする。