メインコンテンツまでスキップ

permitted-contents

HTML Living Standardに基づき、HTML要素のコンテンツモデルと構造的な制約を検証します。@markuplint/html-specに設定値を持っています。

以下の場合に警告します:

  • 親要素のコンテンツモデルで許可されていない子要素やテキストノードが存在する
  • 禁止された祖先要素の子孫として要素が出現している(例: <header>内の<header>
  • 必須の祖先要素が存在しない(例: <map>外の<area>
  • 兄弟要素間でユニークであるべき属性が重複している(例: 複数の<track default>
  • 非空テキストコンテンツが必要な要素が空またはホワイトスペースのみである(例: <title>label属性のない<option>

オプションに独自のルールを設けることができます。カスタム要素やVueなどのテンプレートエンジン上での要素関係を設定することで、構造を堅牢にできます。

ルールの詳細

❌ 間違ったコード例

<ul>
<div>許可されていないdiv要素</div>
</ul>
<ul>許可されていないテキストノード</ul>

<table>
<thead><tr><th>ヘッダセル<th></tr></thead>
<tfoot><tr><td>許可されていない順番のtfoot要素<td></tr></tfoot>
<tbody><tr><td>ボディセル<td></tr></tbody>
</table>

<!-- 禁止された祖先: header要素はheaderやfooterの子孫として出現してはならない -->
<header>
<div>
<header>許可されていないネストされたheader</header>
</div>
</header>

✅ 正しいコード例

<ul>
<li>リストアイテム</li>
<li>リストアイテム</li>
</ul>

<table>
<thead><tr><th>ヘッダセル<th></tr></thead>
<tbody><tr><td>ボディセル<td></tr></tbody>
<tfoot><tr><td>フッタセル<td></tr></tfoot>
</table>

<header>
<nav>ナビゲーション</nav>
</header>

Interface

{
"permitted-contents": Object[]
}

Options

{
"permitted-contents": {
"options": {
"ignoreHasMutableChildren"?: boolean
"evaluateConditionalChildNodes"?: boolean
}
}
}
PropertyTypeDefault ValueDescription
ignoreHasMutableChildrenboolean"true"動的な構文などで、ミュータブルな子要素を持つ場合は無視します。
evaluateConditionalChildNodesboolean"false"[実験中の機能] 条件付きの子ノードを評価します。

Default Severity

error

詳細

値の設定

  • 型: Array
  • 省略可
  • 初期値: []

ルールを設定したい対象の要素を配列で指定します。次の例はカスタム要素のx-containerx-itemそれぞれにルールを指定していることになります。

{
"rules": {
"permitted-contents": [
{
"tag": "x-container",
"contents": []
},
{
"tag": "x-item",
"contents": []
}
]
}
}

tag

  • 型: string
  • 省略不可

対象の要素(タグ)名を指定します。大文字小文字は区別しません。

contents

対象の許可する要素を配列で指定します。この配列の順番は許可するコンテンツの順番を意味します。(この配列に含まれないコンテンツは、すなわち許可されないコンテンツになります)

requireoptionaloneOrMorezeroOrMorechoiceの5つのいずれかのキーワードを使って定義します。

そのうちrequireoptionaloneOrMorezeroOrMoreは要素の個数を意味します。そのキーワードをキーとしてタグ名(もしくはテキストノードの場合 #text)を指定します。それぞれのキーワードを同時に指定できません。

{
"rules": {
"permitted-contents": [
{
"tag": "x-container",
"contents": [
{ "require": "x-item" },
{ "optional": "y-item" },
{ "oneOrMore": "z-item" },
{ "zeroOrMore": "#text" },
// ❌ キーワードの同時の指定はできない
{
"require": "x-item",
"optional": "y-item"
}
]
}
]
}
}
キーワード意味
require必ず1個必要
optional0個か1個
oneOrMore1個かそれ以上
zeroOrMore0個かそれ以上

任意個数の上限を max キーで指定できます。また、 require を指定するときには下限の min キーを設定できます。

組み合わせによっては、次の2つの指定は同じ意味となります。

{ "optional": "tag", "max": 5 }
{ "zeroOrMore": "tag", "max": 5 }

choiceキーワードは指定した配列に対して次の意味をもちます。

キーワード意味
choiceいずれか1つ
{
"rules": {
"permitted-contents": [
{
"tag": "x-container",
"contents": [
{
"choice": [{ "oneOrMore": "x-item" }, { "oneOrMore": "y-item" }]
}
]
}
]
}
}

pretendersオプションと併用したタグルール

pretenders設定によって要素がHTML要素にマッピングされている場合(たとえばJSXコンポーネント<Breadcrumbs><nav>として扱う場合)、このルールは要素を2つの独立したパスで検証します。

  1. Pretendedパス — pretender先のHTMLコンテンツモデル(例: <nav>)に基づいて検証します。他のルールが要素を見るのと同じ方法で、従来の動作に一致します。
  2. Originパス — コンポーネントの元の名前(ソースコードに現れる識別子)をキーにしたタグルールを宣言している場合、pretenderコンテキストを一時的に抑制した状態でそのルールを追加評価します。これにより子要素セレクターはコンポーネント名(例: BreadcrumbList)で一致し、pretender先の<ol>ではなく<BreadcrumbList>にマッチします。

Originパスは以下の両方の条件を満たすときのみ実行されます。

  • 要素がpretenderマッピングを持つ(pretenders設定またはas属性経由)かつ
  • permitted-contents設定にtagがコンポーネントのソースレベル名と一致するエントリが存在する

ユーザーがコンポーネント名向けのタグルールを宣言していない場合、Originパスはスキップされ、ルールはこれまでと完全に同じ挙動を示します。既存の設定が影響を受けることはありません。

{
"pretenders": [
{ "selector": "Breadcrumbs", "as": "nav" },
{ "selector": "BreadcrumbsLabel", "as": "span" },
{ "selector": "BreadcrumbList", "as": "ol" },
{ "selector": "BreadcrumbItem", "as": "li" },
{ "selector": "BreadcrumbLink", "as": "a" }
],
"rules": {
"permitted-contents": [
{
"tag": "Breadcrumbs",
"contents": [{ "optional": "BreadcrumbsLabel" }, { "require": "BreadcrumbList" }]
},
{ "tag": "BreadcrumbList", "contents": [{ "oneOrMore": "BreadcrumbItem" }] },
{ "tag": "BreadcrumbItem", "contents": [{ "require": "BreadcrumbLink" }] },
{ "tag": "BreadcrumbLink", "contents": [{ "require": "#text" }] }
]
}
}

この設定により、ルールはコンポーネントレベルの構造(Originパス)pretend先のHTMLコンテンツモデル(<nav>/<ol>/…)を同時に強制します。2つのパスは独立に違反を報告するため、両方のビューに違反する子ノードには複数の診断が付く場合があります。これは各視点からのエラーを作者が確認できるよう意図されたものです。

ignoreHasMutableChildrenオプションの設定

  • 型: boolean
  • 初期値: true

Pugのようなプリプロセッサ言語やVueのようなコンポーネントライブラリにおけるミュータブルな子要素を含む場合、無視します。(Pug も、Vueも、それぞれ@markuplint/pug-parser@markuplint/vue-parserが必要です)

html
// 本来であればhead要素にtitle要素が含まれないため警告されますが、includeのようなミュータブルな要素を含むため、無視されます。
head
include path/to/meta-list.pug
body
p lorem...