Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor processMarkdown and DocumentProcessorFactory to support arbitrary unified processors #541

Open
u1f992 opened this issue Nov 13, 2024 · 5 comments

Comments

@u1f992
Copy link
Contributor

u1f992 commented Nov 13, 2024

cc: @Mura-Mi

#526 でunifiedプロセッサを注入できるようになりましたが、processMarkdownではVFMのreadMetadataを実行しており、指定したプロセッサとは関係なく一度remark-parseでパースしています。そのため、実際にはremark-parseでエラーが発生しないMarkdown記法しか組み込めません。Markdownは寛容なので大抵は不正確にパースされた上でmetadataにでたらめな値が返るだけですが、正しく処理されない拡張Markdownも考えることはできます。

デフォルトのdocumentProcessorから返されるプロセッサを、VFMを直接使用する形からreadMetadataを行った後パースする実装に変更することで、processMarkdownからreadMetadataを取り除き、任意のunifiedプロセッサ・任意の文書形式を使用できるようになると考えています。DocumentProcessorFactoryの引数からもmetadataは取り除かれます。

たたき台案(参考:https://github.com/orgs/unifiedjs/discussions/113#discussioncomment-234473

const defaultVFMFactory = (options) =>
    unified().use(function () {
        this._vfm = VFM(options);
        this.Parser = (text, file) => {
            this._vfm = VFM(options, readMetadata(text));
            return this._vfm.runSync(this._vfm.parse(file), file);
        };
        this.Compiler = (node, file) => {
            return this._vfm.stringify(node, file);
        };
    });

DocumentProcessorFactoryの引数からmetadataを取り除くデメリットとして、metadataを変更してVFMプロセッサで使用するカスタムプロセッサは作成しづらくなります。しかし、メタデータの多くはhastに変換後もdocumentProcessor: (options) => defaultVFMFactory(options).use(/* metadata操作プラグイン */)のような形で操作できるので問題は少ないと考えます。

@spring-raining
Copy link
Member

Metadata (= Frontmatter) を変更するという使い道以外にも、Metadataの内容に応じて documentProcessor の動作を変える使い道は多くあると考えれられるので、この変更は影響が大きすぎるように思います。例えばVFMの readMetadata 自体を修正して、Markdown全体ではなくFrontmatterのみをパースするように変更することで問題は解決できないでしょうか?

@u1f992
Copy link
Contributor Author

u1f992 commented Nov 14, 2024

指定したdocumentProcessor以外のプロセッサが原稿を処理することが問題で、Frontmatterのみをパースすることは改善にはならない気がします。またreadMetadataではFrontmatterだけではなくHTML全体からメタデータにあたる値を取り出しているように見受けられます。誤解していたらすみません。
先の案はもちろん綺麗な方法ではないと承知していますが、プロセッサはもはやVFMではない可能性がある以上、あくまでVFM側の処理であるreadMetadataはVFMを使用する場合のみ実行されるようにする(VFM、正確にはremark-parseと一連のTransformersでエラーにならないMarkdownからしか有効な値を得られないmetadataは、より抽象度の高いdocumentProcessorからは利用できない)のが本義だとは思います。

あまり根本的でないが手っ取り早い代案として、readMetadataの例外を握りつぶしたうえで、DocumentProcessorFactoryとして引数が一つの関数も許容し、第二引数metadataは「VFMとしてパースした場合に得られるメタデータ(妥当な値かは原稿フォーマット次第)」という形にする手はありそうです。

@spring-raining
Copy link
Member

readMetadataではFrontmatterだけではなくHTML全体からメタデータにあたる値を取り出しているように見受けられます。

こちらは確認したところ確かにその通りで、タイトルを取得するなどの処理に使われていることを確認しました。

とはいえ、documentProcessor の実装者が metadata の情報を受け取れなくなるデメリットのほうが重要で、極力今回のようなBreaking changeは避けたいです。あくまでVivliostyle CLIがサポートするMarkdownはVFMであり、デフォルトのVFMのプロセッサでパースに失敗するのであれば、利用者自身がMarkdown→HTMLのプロセッサを用意してVivliosytle CLIには変換後のHTMLを参照させるということも可能です。そのため、

readMetadataの例外を握りつぶしたうえで、DocumentProcessorFactoryとして引数が一つの関数も許容し、第二引数metadataは「VFMとしてパースした場合に得られるメタデータ(妥当な値かは原稿フォーマット次第)」

という解決策が良いのではないかと思います。

@Mura-Mi
Copy link
Contributor

Mura-Mi commented Nov 16, 2024

breaking change を避けるために readMetadata の例外を握りつぶす方針で良いと思いました。ありがとうございます。

config/input でも VFM の readMetadata を利用していたりするので、本来は VFM の行っている「ソース原稿からHTMLへの変換」と「メタデータ抽出」という2つの機能をインターフェイス抽出して換装できるようにし、現行のVFMはその実装の一つ、とするのが理想ですかね… かなり大きな変更になってしまいますが。

@u1f992
Copy link
Contributor Author

u1f992 commented Nov 18, 2024

ありがとうございます、例外を潰す方向で実装してみます。

メタデータ抽出もインターフェイスに切り出すのは、しっくりきました。VFMのreadMetadataで正しくメタデータを抽出できない文書を仮定するにしても、何らかのしくみでメタデータは含むのだろうと思いますし、そのメタデータでプロセッサ生成の挙動を変えたいという需要も理解します。現状はあくまでVFMを前提とするということで例外を潰す程度で妥当ですが、将来的にVivliostyle CLIがunifiedプロセッサを通じてあらゆる文書形式に対応する想定になるなら、この方式はありえると思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants