architecture/reserved-name-placement · 予約名の配置
予約ディレクトリ名は、その名前について宣言した場所にしか現れてはいけません。
重大度: info · カテゴリ: architecture
チェック内容
予約ディレクトリ名が、その名前について宣言したどの位置にもマッチしない場所に現れている箇所を検出
します。parts について宣言したどの場所にも当てはまらないところに parts/ が現れる、といった
ケースです。
このルールは設定するまで無効です。3 つの配置マップはすべて既定で {} です。
なぜ重要か
architecture/reserved-directory-names は**「この位置では、これらの名前だけ」**と言います。これは
**「この名前は、これらの位置だけ」**とは言えません。複数の種類の場所(ユニットの直下、グルーピング
ディレクトリの直下、ルートディレクトリの直下)に同時に許可される名前について、姉妹ルールは他のどこかに
現れたコピーについて何も言えないからです。1 つの場所のために予約された名前は、別の場所に現れた瞬間に
その意味を失います。1 つの例外に出会った読み手は、そのディレクトリが何を持っているかを知るために
毎回中を開かなければならなくなります。
修正方法
ディレクトリをその名前について宣言済みの場所のいずれかに移動するか、リネームするか、この場所をその 名前について宣言してください。
設定
| オプション | 型 | デフォルト |
|---|---|---|
placements |
予約名 → 親ディレクトリにマッチする | 区切りの glob のマップ |
{} |
capitalisedUnitPlacements |
予約名 → 直下に置ける大文字始まりのユニットディレクトリにマッチする glob のマップ | {} |
anyCaseUnitPlacements |
予約名 → 直下に置ける大文字小文字を問わないユニットディレクトリにマッチする glob のマップ | {} |
exclude |
ディレクトリ glob のリスト | [] |
export default {
rules: {
'architecture/reserved-name-placement': {
options: {
// 名前が A–Z で始まり同名の子ファイルを持つユニットの直下
capitalisedUnitPlacements: { parts: 'src/**', styleGuide: 'src/**' },
// 大文字小文字を問わないユニットの直下
anyCaseUnitPlacements: {
tests: 'src/**',
functions: 'src/**',
stores: 'src/**',
types: 'src/**'
},
// 親ディレクトリ自体を glob で指定
placements: {
functions: 'src/lib/features/*|src/lib/features/*/*|src/routes/**',
stores: 'src/lib/features/*|src/lib/features/*/*',
types: 'src/lib/features/*|src/lib/features/*/*|src/lib/db',
e2e: 'src/routes|src/routes/**',
components: 'src/routes|src/routes/**|src/lib'
},
exclude: ['src/lib/api/**']
}
}
}
};
3 つのマップはすべて同じディレクトリにマッチする
3 つとも予約名の親ディレクトリにマッチし、違いはそのディレクトリにさらに何を求めるかだけです。
placements はそれ以上何も求めず、capitalisedUnitPlacements はそれが名前 A–Z で始まり同名の子
ファイルを持つユニットであることを求め(architecture/reserved-directory-names の isUnitDir)、
anyCaseUnitPlacements は文字の条件を除いた同じ判定を求めます。
位置は 3 つのマップの和集合
ある名前が許可される位置は、3 つのマップにまたがるエントリの和集合です。どのマップにも現れない
名前は対象になりません。上の例で functions が anyCaseUnitPlacements と placements の両方に
現れているのはこのためです。実際の規約は、1 つの名前をユニットの直下・グルーピングディレクトリの直下・
ルートディレクトリの直下に同時に許可することがあり、各名前がちょうど 1 つのマップにしか属せない設計
では、それを表現できません。
| で選択肢を区切り、空の値は名前全体を対象外にする
値は | 区切りの glob のリストで、そのいずれか 1 つがその位置を許可すれば十分です。分割した結果が
空になる値、たとえば placements: { e2e: '|' } は、それを持つマップだけでなくすべてのマップでその
名前を対象外にし、かつ報告されます。空の値だけを落とすと和集合が縮んでしまい、書き間違いが、
その空になったエントリが担っていたすべての位置で偽陽性に変わってしまいます。
ユニットマップの素の glob はユニット自身にマッチする
capitalisedUnitPlacements と anyCaseUnitPlacements は、名前が直下に置かれるユニット
ディレクトリ自体にマッチし、その下にあるだけの祖先にはマッチしません。したがって
parts: 'src/lib' は、ちょうど src/lib にあるユニットの直下でしか parts/ を許可しません。
lib は小文字なので capitalised マップでは到達不能です。一方 parts: 'src/lib/**' は
src/lib 配下のどのユニットの直下でも許可します。素の glob が到達するのは、それが指す 1 つの
ディレクトリだけです。読み手が「このパス配下のどのユニットでも」という意味で書いた場合は間違いに
なります。src/lib は capitalised マップでは決してユニットになり得ないため、報告されます。
読み手が意図してその 1 つの実在するユニットを指定した場合は正しく、報告されません。
parts: 'src/lib/Card' は、ちょうど src/lib/Card にあるユニットの直下でのみ parts/ を許可
し、parts/ がそこにある限り finding は生じません。src/lib ではなく src/lib/** と書くべき
なのは、前者の場合だけです。
exclude
exclude は、姉妹ルールと同様に、ディレクトリとその配下すべてを対象から除外します。下で述べる宣言に
ついての診断は、overrides レイヤーが追加する exclude ではなく、設定ファイル自身が宣言した
exclude に照らして判定されます。配置違反の finding のほうはどちらも尊重します。overrides
レイヤーは除外の追加しかできないため、これによって診断が静かになることはあっても、うるさく
なることはありません。
制限
対象は src/ 配下のディレクトリだけです。
宣言が書いてある内容を実際には検査していない場合は報告されるので、書き間違いでルールが黙って何も しない状態にはなりません。finding にはその理由が名前で示されます。
- 値が位置を 1 つも挙げていなかった。この場合、その名前はすべてのマップで対象外になります。
- glob が1 つのディレクトリにもマッチしなかった。これはファイルシステムではなくソースの
棚卸しに照らして判定されます。
src/の外を指す glob や、ツリーにsrc/routesしかないのにsrc/route/**と書いてしまうような書き間違いは、そのディレクトリが実在していても「1 つの ディレクトリにもマッチしなかった」と報告されます。このルールはsrc/の外を一切見ないためです。 - glob が、
excludeが除外せずに残したディレクトリに一度も到達しない。「マッチしたディレクトリは すべて除外されていた」として報告されます。生きているディレクトリにも到達する glob は、そのマッチの 一部が除外されていても、ここでは報告されません。 - ユニットマップの glob が、求める大文字小文字の条件を満たすユニットに、
excludeが除外せずに 残したツリーのどこにも到達しない。「ユニットに一度も到達しない」として報告されます。これは上で 述べた素の glob の書き間違いを実際に検出します。parts: 'src/lib'は capitalised ユニットに まったく到達しません(ちょうどsrc/libにあるユニットは、libが小文字なので到達不能だから です)。src/libではなくsrc/lib/**と書いてください。
ある名前が現れてよい場所を示す宣言は、それが使われていないからといって無効ではありません。 まだどのディレクトリも使っていない、正当だが現状空の位置は、意図的に何も報告しません。これは上の どの場合にも当てはまりません。読み手が頼ってよい規則はこうです。宣言はその glob が実際に到達 できるかで判定されるのであって、たまたま行使したかどうかでは判定されません。まだどのディレクトリも 占めていない位置に対する正しい宣言は黙ったままであり、一方でユニットがまだ存在しないサブツリーに 絞った glob は、まだ存在しないディレクトリを指す glob と同じ扱いで、それでも報告されます。
このルールが意図的に扱わないものが 2 つあります。予約名ディレクトリでの過剰許可(同じ深さにある グルーピングディレクトリと予約名ディレクトリを glob で区別できないため)と、ツリーから宣言を 生成することです。
モードによる違い
ありません。このルールが読むのは、ファイル内容ではなくプロジェクトのソースファイル一覧(src/** のパス)です。この一覧は CLI、Vite プラグインのビルド、ライブダッシュボードの静的ベースラインのいずれでも同じように作られるため結果は同一で、レンダリング済み HTML の解析で再評価されることもありません。--route で実行範囲を絞ると、このルールは動きません。一覧が作られず、ファイルの検出には紐づけるルートも無いためです。
無効化
個別に抑制するには、対象行の直前に <!-- svelte-vitals-disable-next-line architecture/reserved-name-placement --> を置きます。ルールごと無効化するには、次のように設定します。
export default {
rules: {
'architecture/reserved-name-placement': 'off'
}
};