メインコンテンツまでスキップ
バージョン: v2 Next 🚧

プロジェクト構成

このフレームワークでは、規約がそのまま構造です。エントリポイントと 同じ階層の種別名ディレクトリが自動で走査され、決められた場所に 決められた形のクラスを置くことが、そのまま登録になります:

src/
├── index.ts ← エントリポイント(この階層が自動探索のルート)
├── commands/ ← Command を置く
│ └── PingCommand.ts
├── listeners/ ← Listener を置く
│ └── ReadyListener.ts
├── preconditions/ ← Precondition(コマンドのガード)を置く
├── services/ ← Service(共有ロジック)を置く
└── config/ ← 設定ディレクトリ(createClient を使う場合)

プラグインが種別を足すこともあります — たとえば公式 Utils プラグインを 使うと tasks/ に定期実行タスクを置けるようになります。どの種別でも 規約は同じです。

自動探索のルートはエントリファイルの場所

自動探索のルート(baseDirectory)の既定は、実行したエントリファイル のあるディレクトリです(src/index.ts を実行すれば src/)。 設定ディレクトリの既定の場所 (src/config/)も同じ規則で決まります。

エントリファイルは動かさない

baseDirectory はエントリファイルに追従するため、エントリを別の場所へ 動かすとエラーも出さずに全ストアが空になります。起動チェック用 スクリプトのように2つめのエントリを作る場合は、1つめと同じディレクトリに 置いてください(src/index.tssrc/check.ts)。どちらを bun run しても同じ config/ と同じ baseDirectory が導かれます。

ルートは new Client({ baseDirectory }) で明示でき、null を渡すと 自動探索そのものを無効化できます(明示登録のみになります — コンポーネント)。

名前はクラス名から決まる

コンポーネント名は、クラス名から種別サフィックスを除去して導出 されます。種別ごとに自然な形に整えられます:

種別変換
CommandケバブケースPingCommandpingUserInfoCommanduser-info
ListenerケバブケースReadyListenerready
Precondition大文字小文字を保持OwnerOnlyPreconditionOwnerOnly
ServicelowerCamelCaseConfigServiceconfigGuildSettingsServiceguildSettings

導出名を使いたくない場合は @X.define({ name: "..." }) で明示できます。 名前はストア内で一意で、衝突は起動時エラーです。

サブディレクトリは整理のためだけ

各ディレクトリの中はサブディレクトリで自由に分けられます (commands/music/PlayCommand.ts など)。サブディレクトリは整理の ためだけで、コンポーネント名には影響しません — 名前は常にクラス名から 決まります(commands/music/PlayCommand.tsplay)。

_ で始まるファイルは読み込まれない

_ で始まるファイルとディレクトリは共有コード扱いで、自動探索から スキップされます。コマンド間の共通処理は commands/_shared.tscommands/_internal/ に置き、各ファイルから普通に import してください。

そのほかにスキップされるもの:

  • 型定義(*.d.ts)
  • テスト(*.test.* / *.spec.*)
  • クラスでない export、種別と無関係な export

読み込み順はパスのソート順です — 決定的ですが、名前とは無関係です。

config/ は設定ディレクトリ

config/ はコンポーネント種別のディレクトリと同じ並びに置きますが、 コンポーネントではなく設定ファイルの置き場です(config という 名前のストアは存在しないので、自動探索に拾われることはありません)。 詳しくは設定ディレクトリを参照して ください。