Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/calm-doors-declare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@svelte-vitals/core': minor
'svelte-vitals': minor
'@svelte-vitals/vite': minor
Comment thread
coderabbitai[bot] marked this conversation as resolved.
---

Add two declaration-driven rules, `a11y/disallowed-element` and `a11y/required-element`. Both are inert until a project declares tag names in their `elements` option (`{ options: { elements: ['iframe'] } }`); an `overrides` entry adds to the list for the routes or files it matches. `disallowed-element` reports every occurrence of a declared tag in component source. `required-element` judges the composed route — layout chain, page, resolved components, and `app.html`'s `<body>` — so a layout's `<main>` counts; presence passes in any world, and a missing element is reported only where the route is closed for elements (build mode always; static mode where every component resolved and there is no `{@html}` or `<svelte:element>`).

The `elements` declaration is a bare tag name — letters, digits, hyphens — and selector syntax is rejected when the config loads, so a later attribute-qualified form can be added without changing what today's configs mean. `string-list` rule options can now declare a `pattern` for this.
12 changes: 9 additions & 3 deletions docs/blume.translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"ja": "3976965c8e7b613f"
},
"src/content/docs/guides/(setup)/configuration.mdx": {
"ja": "4b46787d5141e424"
"ja": "d18a2021fff3c072"
},
"src/content/docs/guides/(setup)/install.md": {
"ja": "0d7e310a8799a4cb"
Expand Down Expand Up @@ -66,6 +66,9 @@
"src/content/docs/rules/a11y/disallowed-aria-props.md": {
"ja": "a7f185c38612ee70"
},
"src/content/docs/rules/a11y/disallowed-element.md": {
"ja": "338ff066f28d3000"
},
"src/content/docs/rules/a11y/doctype.md": {
"ja": "6737bcac2015dc43"
},
Expand All @@ -76,7 +79,7 @@
"ja": "6755668014fe30be"
},
"src/content/docs/rules/a11y/index.mdx": {
"ja": "83dd6044451d9c7c"
"ja": "7aaf98ccdfe319a9"
},
"src/content/docs/rules/a11y/interactive-nesting.md": {
"ja": "9551be5e31e0bb8b"
Expand All @@ -102,6 +105,9 @@
"src/content/docs/rules/a11y/required-aria-props.md": {
"ja": "8c47bd66bdc2fff6"
},
"src/content/docs/rules/a11y/required-element.md": {
"ja": "088d5d9347a83376"
},
"src/content/docs/rules/a11y/top-level-landmark.md": {
"ja": "0504a06497bf1ecd"
},
Expand Down Expand Up @@ -193,7 +199,7 @@
"ja": "ef83c9aa379441ef"
},
"src/content/docs/rules/index.mdx": {
"ja": "6041cfdafa004524"
"ja": "f0359b42b494f323"
},
"src/content/docs/rules/performance/font-preload-crossorigin.md": {
"ja": "afcb16b8a61e3dc1"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/guides/(setup)/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ One exception: `--rules` and `--ignore` are selection, not configuration — eac

## Validation

- **Invalid and svelte-vitals stops (exit `2`)**: the file can't be loaded (syntax error or no default export); an unknown rule id inside `rules`; an unknown category or a negative/non-numeric value inside `weights`; a malformed `overrides` entry (not `{ route/files, rules }`-shaped, a scope that isn't a string / non-empty string array, or a key in its `rules` that is neither a known rule id nor a category); an invalid rule setting, in either `rules` or an `overrides` entry's `rules` — a bare string other than `off`/`critical`/`warning`/`info`, an object form with an unrecognized key or an invalid `severity`, options on a rule that takes none, an unknown option name, an option value of the wrong type or out of range, options on a category key, or (for a rule with both a `min` and a `max` option) a configured range where `min` would exceed `max`.
- **Invalid and svelte-vitals stops (exit `2`)**: the file can't be loaded (syntax error or no default export); an unknown rule id inside `rules`; an unknown category or a negative/non-numeric value inside `weights`; a malformed `overrides` entry (not `{ route/files, rules }`-shaped, a scope that isn't a string / non-empty string array, or a key in its `rules` that is neither a known rule id nor a category); an invalid rule setting, in either `rules` or an `overrides` entry's `rules` — a bare string other than `off`/`critical`/`warning`/`info`, an object form with an unrecognized key or an invalid `severity`, options on a rule that takes none, an unknown option name, an option value of the wrong type, out of range, or not in the grammar the option declares (a tag-name list given a selector), options on a category key, or (for a rule with both a `min` and a `max` option) a configured range where `min` would exceed `max`.
- **Invalid but ignored, with a warning (analysis still runs)**: an unrecognized `treatDynamicAs` or `failOn` value (falls back to flag/default); an unrecognized top-level key (forward-compatible with future config fields).

## TypeScript configs
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/ja/guides/(setup)/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ CLI の静的モードは、ルートの `<head>` と見出しを解決するた

## バリデーション

- **無効で svelte-vitals が停止する(終了コード `2`)**:ファイルを読み込めない(構文エラー、または default export がない場合)、`rules` 内に未知のルール ID がある、`weights` 内に未知のカテゴリまたは負の値や数値でない値がある場合、`overrides` のエントリが不正な場合(`{ route/files, rules }` の形でない、スコープが文字列でも空でない文字列配列でもない、`rules` 内のキーが既知のルール ID でもカテゴリ名でもない)、`rules` または `overrides` エントリの `rules` 内のルール設定が不正な場合(`off`/`critical`/`warning`/`info` 以外の文字列、未知のキーを含むオブジェクト形式、オブジェクト内の不正な `severity`、オプションを受け付けないルールへの `options`、未知のオプション名、型が誤っているか範囲外のオプション値、カテゴリのキーへの `options`、または `min` と `max` の両方を持つルールで `min` が `max` を超える範囲になっている場合のいずれか)。
- **無効で svelte-vitals が停止する(終了コード `2`)**:ファイルを読み込めない(構文エラー、または default export がない場合)、`rules` 内に未知のルール ID がある、`weights` 内に未知のカテゴリまたは負の値や数値でない値がある場合、`overrides` のエントリが不正な場合(`{ route/files, rules }` の形でない、スコープが文字列でも空でない文字列配列でもない、`rules` 内のキーが既知のルール ID でもカテゴリ名でもない)、`rules` または `overrides` エントリの `rules` 内のルール設定が不正な場合(`off`/`critical`/`warning`/`info` 以外の文字列、未知のキーを含むオブジェクト形式、オブジェクト内の不正な `severity`、オプションを受け付けないルールへの `options`、未知のオプション名、型が誤っているか範囲外、またはオプションが宣言する文法に合わないオプション値(タグ名のリストにセレクタを書いた場合)、カテゴリのキーへの `options`、または `min` と `max` の両方を持つルールで `min` が `max` を超える範囲になっている場合のいずれか)。
- **無効だが無視され、警告が出る(分析は続行される)**:認識できない `treatDynamicAs` または `failOn` の値(フラグ/デフォルトにフォールバック)、認識できないトップレベルキー(将来の設定フィールドとの前方互換性のため)。

## TypeScript の設定ファイル
Expand Down
57 changes: 57 additions & 0 deletions docs/src/content/docs/ja/rules/a11y/disallowed-element.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
title: a11y/disallowed-element · 禁止された要素
description: プロジェクトが「使わない」と宣言した要素の出現をすべて報告します — 宣言するまでは何もしません。
---

**重大度:** warning · **カテゴリ:** a11y

宣言駆動のルールで、ルール自身の意見はありません。何も宣言しなければ何もせず、プロジェクトが使いたくないタグを宣言すれば、その出現がすべて検出になります。

## チェック内容

コンポーネントのソース中で、タグ名が宣言リストに含まれるすべての要素。CLI と Vite プラグインの両方が同じ `.svelte` を読むので、どちらでも対象です。`--route` で実行範囲を絞ると、このルールは動きません — コンポーネントスコープのルールには、検出を紐づけるルートが無いためです。

```js svelte-vitals.config.js
export default {
rules: {
'a11y/disallowed-element': { options: { elements: ['iframe', 'marquee'] } }
}
};
```

`elements` は**素のタグ名**のリストです — 先頭は英字、続けて英数字とハイフンなので、カスタム要素名(`my-widget`)も書けます — 大文字小文字は区別しません。それ以外(`input[type=file]`、`.legacy`、`div > p`)は config 読み込み時に拒否されます。受理してしまうと黙って何にもマッチしない値になり、後で意味を与えると受理済みの config の意味が変わってしまうためです。宣言を「どこに」効かせるかは、他のルールと同じく `overrides` の役割です。`files` や `route` を持つエントリは、マッチしたファイルに対してリストに**追加**します(`string-list` オプションは追加であって置換ではありません)。

```js svelte-vitals.config.js
export default {
rules: {
'a11y/disallowed-element': { options: { elements: ['iframe'] } }
},
overrides: [
{ files: 'src/routes/(marketing)/**', rules: { 'a11y/disallowed-element': { options: { elements: ['video'] } } } }
]
};
```

検出は要素の開始タグの行に紐づくので、タグが何行にまたがっていても、直上の `<!-- svelte-vitals-disable-next-line a11y/disallowed-element -->` 1 つで抑制できます。要素があり禁止要素のないコンポーネントは pass になります。

見えないもの: `<svelte:element this="iframe">` — `this` がリテラルでも、収集器にとってタグは動的です。

## なぜ重要か

そのプロジェクトのマークアップに居場所のない要素があります — コンテンツページの `<iframe>`、移行途中のレガシーなカスタム要素、どこであれ `<font>` — そしてレビューコメントはスケールしません。ここで宣言すれば、ルールがレビュアーになり、他の検出と同じくスコアされ gate されます。

## 修正方法

プロジェクトが好む要素に置き換えるか、許可するファイルについて `overrides` エントリで宣言を絞ります。

## 無効化

個別の要素を抑制するには `<!-- svelte-vitals-disable-next-line a11y/disallowed-element -->` を置きます。宣言を消すか、ルールごと無効化するには:

```js svelte-vitals.config.js
export default {
rules: {
'a11y/disallowed-element': 'off'
}
};
```
Loading