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
16 changes: 16 additions & 0 deletions .changeset/reserved-directory-names-any-case-units.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@svelte-vitals/core': minor
---

Add `anyCaseUnitScopes` to `architecture/reserved-directory-names`: a counterpart to `unitScopes` that
governs units whose name does not begin A–Z.

`unitScopes` identifies a unit with `isUnitDir`, which requires the directory name to begin A–Z as well
as holding a same-stemmed child file — so a lowercase, `.ts`- or `.svelte.ts`-entry unit's children (measured
at 129 of 299 units, 43%, on a real tree) were never governed by any declaration. `anyCaseUnitScopes` takes
the same option shape against `isAnyCaseUnitDir`, the same test without the letter requirement. Declaring
the identical glob in both maps is not a collision: `unitScopes` governs at capitalised units,
`anyCaseUnitScopes` governs alone at the lowercase ones `unitScopes` never reaches.

Default behavior is unchanged — `anyCaseUnitScopes` defaults to `{}`, so a project that does not declare it
sees no new findings.
3 changes: 2 additions & 1 deletion docs/src/content/docs/guides/(setup)/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ section with its exact option names and defaults.
directory glob to casing set, and `exclude` globs. The rule is inert until you set `directories`.
- [`architecture/reserved-directory-names`](/rules/architecture/reserved-directory-names) — `scopes`
(directory glob → allowed child names), `unitScopes` (root glob → the names a unit's children may
take) and `exclude`. Off until one of the two is set.
take), `anyCaseUnitScopes` (the same, for units of either case) and `exclude`. Off until a scope map
is set.
- [`architecture/route-component-import`](/rules/architecture/route-component-import) — an
`exemptImporters` glob list of satellite files (stories, tests, specs) allowed to import a route
entry by hand, added to the built-in list.
Expand Down
3 changes: 2 additions & 1 deletion docs/src/content/docs/ja/guides/(setup)/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ export default {
何も出力しません。
- [`architecture/reserved-directory-names`](/ja/rules/architecture/reserved-directory-names) —
`scopes`(ディレクトリ glob → 直下に置ける名前)、`unitScopes`(起点 glob → ユニット直下に置ける
名前)、`exclude`。どちらかを設定するまで無効です。
名前)、`anyCaseUnitScopes`(同様、大文字小文字を問わないユニット用)、`exclude`。いずれかの
スコープマップを設定するまで無効です。
- [`architecture/route-component-import`](/ja/rules/architecture/route-component-import) —
ルートエントリを手動でインポートしてよいサテライトファイル(stories、test、spec)を指定する
`exemptImporters` の glob リスト。組み込みリストに追加されます。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ description: ディレクトリの直下に置ける名前は、その位置に

## 設定

| オプション | 型 | デフォルト |
| ------------ | --------------------------------------------- | ---------- |
| `scopes` | ディレクトリ glob → 直下に置ける名前 のマップ | `{}` |
| `unitScopes` | 起点 glob → 直下に置ける名前 のマップ | `{}` |
| `exclude` | ディレクトリ glob のリスト | `[]` |
| オプション | 型 | デフォルト |
| ------------------- | ------------------------------------------------------------------------- | ---------- |
| `scopes` | ディレクトリ glob → 直下に置ける名前 のマップ | `{}` |
| `unitScopes` | 起点 glob → 直下に置ける名前 のマップ(名前が A–Z で始まるユニット用) | `{}` |
| `anyCaseUnitScopes` | 起点 glob → 直下に置ける名前 のマップ(大文字小文字を問わないユニット用) | `{}` |
| `exclude` | ディレクトリ glob のリスト | `[]` |

```js
// svelte-vitals.config.js
Expand All @@ -44,14 +45,15 @@ export default {
'architecture/reserved-directory-names': {
options: {
scopes: { 'src/lib': 'api|components|features|effect|db' },
unitScopes: { 'src/**': 'parts|functions|stores|types|tests|styleGuide' }
unitScopes: { 'src/**': 'parts|functions|stores|types|tests|styleGuide' },
anyCaseUnitScopes: { 'src/**': 'functions|stores|types|tests' }
}
}
}
};
```

### 2 つのオプションはキーが何を指すかが違う
### スコープマップはキーが何を指すかが違う

**`scopes` のキーは親を直接指します。** `'src/lib'` は `src/lib` にマッチし、その直下のサブ
ディレクトリが取り得る名前は、あなたが列挙したものになります。
Expand All @@ -62,6 +64,15 @@ export default {
`Card/Card.svelte.ts`)。glob が届かない対象 —— ユニットは任意の深さで入れ子になるため —— に対する
閉じた集合には、これを使ってください。

**`anyCaseUnitScopes` のキーも起点を指しますが、大文字小文字を問わないユニットを対象にします** ——
文字の条件を除いた同じ判定で、`.ts` や `.svelte.ts` を entry とするユニット
(`formatDate/formatDate.ts`、`useThing/useThing.svelte.ts`)も数えます。`unitScopes` の文字条件は
小文字のユニットを除外するため、このオプションがなければ汎用のユニットマップ宣言がその子を検査する
ことはありませんでした —— 親を直接指す `scopes` のキーであれば届くことがあります —— 実測では 299
ユニット中 129(43%)が該当しました。どちらのユニットオプションも裸の「unit」という語では命名して
いません —— 同じ分割を自身のオプションに採用している `architecture/reserved-name-placement` が、
両方の判定が存在するとその語だけでは曖昧になる理由を記録しています。

`scopes` のキーは、子が**すべて**列挙した名前から成る場合にのみ書く価値があります。ルート
ディレクトリは予約名とルートセグメントを並べて持ちますが、ルートセグメントは無制限です —— ページごとに
1 つ —— ので、そこに宣言を置くべきではありません。それでも書けば、すべてのセグメントが報告されます。
Expand All @@ -77,17 +88,35 @@ export default {

### どの宣言が優先されるか

両方のマップが 1 つのディレクトリにマッチした場合は、より特異なキーが優先されます。パスの
複数のマップが 1 つのディレクトリにマッチした場合は、より特異なキーが優先されます。パスの
セグメント数が多いほうが先、同数なら `**` セグメントが少ないほう、それも同じならキーが長いほう、
最後に辞書順です。これによって、どちらのマップも他方を狭めることができます。
最後に辞書順です。これによって、どのマップも他方を狭めることができます。

**同一の** glob だけは、この手順では分けられない組み合わせで、そこでは固定の優先順位が決めます ——
**`scopes` はどちらのユニットマップにも優先し、`unitScopes` は `anyCaseUnitScopes` に優先します。**

`scopes` がユニットマップに優先するのは、`scopes` がキーのマッチするすべてのディレクトリに適用される
のに対し、ユニットマップはそれぞれが求める大文字小文字のユニットにしか適用されないからです。同じ
glob を `scopes` とユニットマップの両方に宣言すると報告されます。両方が宣言されている範囲では
`scopes` が優先されるため、そこではユニットマップ側のエントリは何もチェックしません。(それ以外の
場所ではなお適用され得ます —— たとえばグローバルに宣言した `unitScopes` のキーが、`overrides`
エントリの中だけで追加された `scopes` のキーに覆われている場合、そのオーバーライドの適用範囲の外
では引き続き適用されます。)

`unitScopes` が `anyCaseUnitScopes` に優先するのは、`unitScopes` の文字条件のほうが 2 つのゲートの
うち狭いからです —— 大文字始まりのユニットは常に大文字小文字を問わないユニットでもありますが、逆は
成り立ちません —— そのため両方のマップに同一の glob を書くと、衝突ではなく**分割**になります。
`unitScopes` は大文字始まりのユニットを対象にし、`anyCaseUnitScopes` は `unitScopes` が届かない
小文字のユニットだけを単独で対象にします。両方のエントリが実際に仕事をしているため、これは無効な
宣言として報告されません。

**同一の** glob だけは、この手順では分けられない唯一の組み合わせで、そこでは `scopes` が優先されます
—— `scopes` はキーがマッチするすべてのディレクトリに適用されるのに対し、`unitScopes` はそのうち
ユニットであるものにしか適用されないからです。同じ glob を両方のマップに宣言すると報告されます。
両方が宣言されている範囲では `scopes` が優先されるため、そこでは `unitScopes` 側のエントリは何も
チェックしません。(それ以外の場所ではなお適用され得ます —— たとえばグローバルに宣言した
`unitScopes` のキーが、`overrides` エントリの中だけで追加された `scopes` のキーに覆われている場合、
そのオーバーライドの適用範囲の外では引き続き適用されます。)
```js
options: {
// 大文字始まりのユニットには parts と styleGuide も許可し、小文字のユニットには許可しない
unitScopes: { 'src/**': 'parts|styleGuide|functions|stores|types|tests' },
anyCaseUnitScopes: { 'src/**': 'functions|stores|types|tests' }
}
```

**末尾**の `/**` は「このディレクトリ配下すべて」を意味し、ディレクトリ自身は対象にしません。

Expand Down Expand Up @@ -128,22 +157,29 @@ options: {
このルールが言うのは「ここでは、これらの名前だけ」であり、「この名前は、ここだけ」とは言えません。
間違った場所にある `parts/` は、その場所自体が宣言されていない限り見えないままです。

**ユニットの直下にユニットを入れ子にするプロジェクトは `unitScopes` を宣言すべきではありません**
—— 入れ子になったユニットは集合に含まれない子となり、報告されてしまいます。
**ユニットの直下にユニットを入れ子にするプロジェクトは `unitScopes` も `anyCaseUnitScopes` も
宣言すべきではありません** —— 入れ子になったユニットは集合に含まれない子となり、報告されてしまいます。

宣言が書いてある内容を実際には検査していない場合は報告されるので、書き間違いでルールが黙って何も
しない状態にはなりません。次の 5 つがこの finding に該当し、それぞれメッセージに名前が出ます。
しない状態にはなりません。次のケースがこの finding に該当し、それぞれメッセージに名前が出ます。

- glob が 1 つのディレクトリにもマッチしなかった
- マッチしたディレクトリがすべて除外されていた
- ディレクトリにはマッチしたがユニットには一度もマッチしなかった
- `unitScopes` のキーがディレクトリにはマッチしたがユニットには一度もマッチしなかった
- `anyCaseUnitScopes` のキーがディレクトリにはマッチしたが、大文字小文字を問わずユニットに一度も
マッチしなかった —— 大文字始まりのユニットは常に大文字小文字を問わないユニットでもあるため、
こちらのほうが強い主張です
- 値が名前を 1 つも列挙していなかった
- 同じ glob が両方のマップに宣言されており、**双方**の値が 1 つ以上の名前を挙げていた。どちらかの値が何も挙げていない場合はマッチ前に捨てられ、もう一方が単独で適用されるため、代わりに「値が名前を 1 つも列挙していない」として報告されます
- 同じ glob が `scopes` とユニットマップの両方に宣言されており、**双方**の値が 1 つ以上の名前を
挙げていた。どちらかの値が何も挙げていない場合はマッチ前に捨てられ、もう一方が単独で適用される
ため、代わりに「値が名前を 1 つも列挙していない」として報告されます。**2 つのユニットマップ**の
両方に同じ glob を宣言した場合はこのケースに当たりません —— 上の「どの宣言が優先されるか」を
参照してください。

意図的にまったく報告されないものが 2 つあります。

- `overrides` エントリの**中だけ**で宣言したキー。何にマッチしたかがそのオーバーライドの適用範囲に
依存するためです。ただし 1 つ例外があり、同一 glob の衝突検査はグローバル宣言に絞られていないため、
`overrides` だけから組み上がった `scopes`/`unitScopes` の衝突は報告されます。
`overrides` だけから組み上がった `scopes` とユニットマップの衝突は報告されます。
- 現在どのディレクトリも使っていない宣言済みの名前。この集合が表すのは現れて**よい**ものであって、
現れなければならないものではないからです。
Loading