vivliostyle/vfm

Should not output "null" for empty value of frontmatter properties

MurakamiShinyu opened this issue · 11 comments

Issue Details

Frontmatter にキーだけ書いて値が空の場合、HTMLでその値が出力されるところに "null" という文字列が出力される。
文字列 "null" は、HTMLにおいて特別な意味がないただの文字列であり、例えば <title>null</title> では "null" というタイトルということになってしまうので適切ではない。

例:

---
lang:
title:
author:
link:
  - rel:
    href:
---

<!doctype html>
<html lang="null">
  <head>
    <meta charset="utf-8">
    <title>null</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="author" content="null">
    <link rel="null" href="null">
  </head>
  <body></body>
</html>
  • VFM version
    • 1.0.0-alpha.24

Expected Behavior

文字列 "null" ではなく、空文字列になるべきだろう。上記の例なら次の出力になってほしい:

<!doctype html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="author" content="">
    <link rel="" href="">
  </head>
  <body></body>
</html>

js-yaml の解析は Key だけある場合に null となるようです。これを判定することは可能です。ただしこの状態を空文字として出力すべきでしょうか?

例えば現在 idlang などのルートにある値を空文字にすると評価部分が if (value) のようになっているため、空文字も偽となって書き込みをスキップします。

空文字として書き込む仕様にするなら全ての値について振る舞いを決める必要があります。null が書き込まれること自体はバグですが、単に空文字として扱うだけでは修正にならないと考えています。

空文字を許容する値については、それを仕様として明示する必要があります。それを持って判定部も単に if (value) とするのではなく空文字も許容するように修正することとなるでしょう。

src/plugins/document.ts の処理をお読みいただけると私の意図がわかりやすいと思います。

手元で空文字変換して langid などオプショナルかつ直値になるもののテストを書いていてこの問題に気づきました。直値ではなく Array になるもの (link など) はその先で空文字をはじいていないため、結果として許容されることになります。

Markdownで原稿を作るプロジェクトによって、Markdownの雛形として、

---
lang:
title:
author:
hoge:
---

のように、値を空にしておいたものを使って、必要に応じてその値を埋める、というような使い方をすると思います。
その場合、値が空のままではエラーになるというのでは使いにくいので、空の値は空文字列 "" と同じ扱いでよいかと考えたのですが、むしろ該当する属性や要素を出力しないというのが、適切かもしれないですね。

補足。js-yaml の変換結果を試したところ

  • key: = null
  • key: "" = ""
  • key: "value" = "value"

でした。明示的に空文字を指定するための "" と暗黙的な空の値を区別する必要があるか?という話です。

@MurakamiShinyu

むしろ該当する属性や要素を出力しないというのが、適切かもしれないですね。

はい。明示的な空文字を指定する方法がある以上、null の場合は読み込み時点で「評価しない = 未定義」とするほうがよさそうです。

ちなみに現時点だと「値なし = null」は

metadata[key] = `${data[key]}`;

のようにしているためエラーにならず、本 issue のように "null" となっています。これを未定義として扱うなら代入部分で判定してはじくように変更します。

すみません↑に補足です。明示的に空文字を指定された場合、つまり key: "" をはじくか否かも決める必要があります。

  • key 自体が未定義 ...出力なし
  • key: ...現状は "null" 扱いで出力、本 issue で指摘されているとおりバグ
  • key: "" ...現状は langid などルートかつオプショナルな値だけ未出力、link など階層化されるものは出力

となっています。これをそれぞれどのようにするか。

HTML仕様で Boolean attributes https://html.spec.whatwg.org/#boolean-attributes は、属性の名前だけ指定しても ="" を指定しても同じで true という意味になります。そのような属性を指定するのに key: "" が指定できることは必要です。これを key: だけの指定でも同じ意味にしても、自然な感じはします。

それもありますね。key を指定している時点で値がなくても出力を期待しているともとれるので。

ここまでの議論を踏まえ、当初案の発展形で

  1. key:key: "" として扱う
  2. langid が null (これは 1 により書き込み側からは "" に見える) または空文字でも "" として出力する

とするのはどうでしょうか?

ではそのようにします。ドキュメントにも記載予定です。

#112 にて対応、それを反映した 1.0.0-alpha.25 をリリースしたので本件は close します。