Markuplintのおすすめ設定 for Svelte

## Markuplintとは
間違っているマークアップがあったら怒ってくれるLinterです。

HTMLがよくわからない人たちにとっても、詳しい人にとっても、常に正しいマークアップに縛ってくれるかなり嬉しいライブラリです。

控えめに言って最高のライブラリです。
これを入れておけばチームにマークアップに疎いメンバーがいてもレビュー前に直してもらうことができますね。
もちろん自分のミスも見つけてくれるのでハッピーです！

## Svelteとアクセシビリティ
デフォルトでアクセシビリティ周りのLintが入っています。

言わずもがな最高のライブラリですね。
**Svelteはいいぞ！**

## Markuplintの設定
最初に設定を公開します。

### .markuplintrc
```json
{
	"extends": [
		"markuplint:recommended"
	],
	"parser": {
		".svelte$": "@markuplint/svelte-parser",
		".html$": "@markuplint/svelte-parser/kit"
	},
	"specs": {
		".svelte$": "@markuplint/svelte-spec"
	},
	"overrideMode": "merge",
	"rules": {
		"permitted-contents": {
			"options": {
				"ignoreHasMutableChildren": false,
				"evaluateConditionalChildNodes": true
			}
		}
	},
	"pretenders": [
		{
			"selector": "List",
			"as": "ul"
		},
		{
			"selector": "ListItem",
			"as": "li"
		},
		{
			"selector": "Slot",
			"as": {
				"element": "slot"
			}
		}
	]
}
```

## svelte:element
Markuplintは例えば

```svelte
<ul>
  <svelte:element this="ul">text</svelte:element>
</ul>
```

このように間違ってulの直下にulタグが来てしまうような書き方をしてしまっても怒ってくれません。

svelte:elementを指定したタグとして認識させたいところですね…。
マークアップがバグり散らかしているとアクセシビリティにも悪影響があるので、できるだけLintで縛って欲しいです。

これは、「as」の仕様を利用すれば解決できます。

 ### as
 Markuplintには[`as`属性にタグ名を入れるとそのタグとして解析してくれる機能](https://markuplint.dev/ja/docs/guides/besides-html#as%E5%B1%9E%E6%80%A7%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)があります。

 #### Element.svelte
 ```svelte
 
<script lang="ts">
	export let as: string;
</script>

<svelte:element this={as}>
	<slot />
</svelte:element>
 ```

svelte:elementのラッパーとしてElement.svelteをこのように作っておくことでMarkuplintにsvelte:elementを指定したタグで解析させることができます。
（欲を言えばthis属性の値をみて欲しい…）

つまり、
```svelte
<ul>
  <Element as="li">text</Element>
</ul>
```

こうすることでsvelte:elementを使っていてもMarkuplintに指定したタグとしてLintしてもらうことができます。
ハッピー！


### TIPS
また、以下のように`{#each}`などで囲むとエラーが出ないようになります。
```svelte
<ul>
  {#each items as item (item)}
    <svelte:element this="li">text</svelte:element>
  {/each}
</ul>
```
これは単純に`{#each}`の下が無視されているだけなので、例えば

```svelte
<ul>
  {#each items as item (item)}
    <p>エラーになって欲しい</p>
    <svelte:element this="li">text</svelte:element>
  {/each}
</ul>
```

このようにしたとしてもエラーにはなりません。

縛りたいですね…。

これは`permitted-contents`のoptionの`evaluateConditionalChildNodes`をtrueに設定することでエラーにすることができます。

それが
```json
	"rules": {
		"permitted-contents": {
			"options": {
				"ignoreHasMutableChildren": false,
				"evaluateConditionalChildNodes": true
			}
		}
	}
 ```

 この部分です。より安全になるので最高ですね。

## Slot
slotで受け取った要素をそのまま表示するコンポーネントを作ることがあるでしょう。

例えば以下のようなSlotコンポーネントです。

```svelte
<slot name="mobile" />
<slot name="laptop" />
```

このコンポーネントは受け取ったslotをそのまま表示するだけで、Slotコンポーネント自体はHTMLを持ちません。

このようなコンポーネントは以下のようにpretendersという機能を使うことでslotのように無視されるコンポーネントとすることができます。

```json
	"pretenders": [
		{
			"selector": "Slot",
			"as": {
				"element": "slot"
			}
		}
	]
```

つまり、以下のように書いてもエラーにならなくなります。
pretendersを使用しない場合、「ulの下にSlotは置けないよ」といったエラーが出ます。
```svelte
<ul>
  <Slot>
    <li slot="mobile">mobileでだけ出すli</li>
    <li slot="laptop">laptopでだけ出すli</li>
  </Slot>
</ul>
```

このようにpretendersは結構なんでもできるとてつもなく便利な機能です。
使い倒しましょう！

他にも、これを使うことでListItemsコンポーネント（liタグで何かを表示する）ようなコンポーネントをliとして扱い、

```svelte
<ul>
  <ListItem>text</ListItem>
</ul>
```
このように書くことができるようになります。
クソ便利ですね〜

Markuplintを使って正しいマークアップになるように、縛っていきましょう！