Custom Elements ManifestのJSX型定義から名前のないイベントを除外

shoelace-style/webawesome

StencilJSとの互換性を高めるため、Custom Elements Manifest(CEM)の解析プロセスから名前のないイベントエントリを除外する仕組みが追加されました。これにより、JSX型定義に onundefined のような不正なイベントハンドラが生成される問題が解消されます。

背景

CEMアナライザーは2つの方法でイベントを検出していました。1つは @event JSDocタグからの検出(イベント名を含む)、もう1つはコード内の dispatchEvent() 呼び出しの解析(型のみで名前を含まない)です。この二重検出により、一部のイベントエントリに名前が欠落し、JSX型生成時に onundefined のような不正なイベントハンドラが生成されていました。

#1919 で報告されたこの問題は、StencilプロジェクトでWeb Awesomeを使用する際に型エラーを引き起こしていました。<wa-button onClick={...} /> のような有効なStencil TSXコードが、Property 'onClick' does not exist というエラーで失敗する状況でした。

問題の根本原因は、dispatchEvent() 呼び出しから検出されたイベントが name プロパティを持たず、JSX型生成器がこれを onundefined として出力していたことです。wa-iconwa-buttonwa-inputwa-selectwa-dialogwa-drawerwa-dropdownwa-tooltip を含む25個のコンポーネントでこの問題が発生していました。

技術的な変更

custom-elements-manifest.jswa-filter-unnamed-events プラグインが追加され、JSX型生成前に名前のないイベントを除外するようになりました。

変更内容:

// Filter out events without names (these come from code analysis detecting
// dispatchEvent() calls, but lack the event name that comes from @event JSDoc tags)
{
  name: 'wa-filter-unnamed-events',
  packageLinkPhase({ customElementsManifest }) {
    customElementsManifest?.modules?.forEach(mod => {
      mod.declarations?.forEach(dec => {
        if (dec.kind === 'class' && dec.events) {
          dec.events = dec.events.filter(event => event.name);
        }
      });
    });
  },
},

このプラグインは packageLinkPhase で動作し、CEM内の各クラス宣言の events 配列から name プロパティを持たないエントリをフィルタリングします。

JSX型生成の設定にも変更が加えられました:

jsxTypesPlugin({
  fileName: 'custom-elements-jsx.d.ts',
  outdir,
  defaultExport: true,
  includeDefaultDOMEvents: true,  // 追加
  componentTypePath: (_name, _tag, modulePath) => {
    return `./${modulePath}`;
  },
}),

includeDefaultDOMEvents: true が追加され、onClick のような標準DOMイベントがJSX型定義に含まれるようになりました。これにより、StencilプロジェクトでWeb Awesomeコンポーネントに標準イベントハンドラをバインドできるようになります。

設計判断

イベント検出の仕組み自体を変更するのではなく、型生成前のフィルタリング というアプローチが採用されました。

コード解析による dispatchEvent() の検出は、開発者が @event タグを付け忘れた場合のフォールバックとして有用です。しかし、この検出方法では呼び出し箇所から型情報しか取得できず、イベント名は得られません。両方の検出方法を維持しつつ、名前のないエントリだけを除外することで、@event タグで明示的に宣言されたイベントと、タグがあってコードにも実装があるイベントの両方を適切に処理できます。

PR内の議論では、ビルドプロセスに検証ステップを追加することも提案されました。CEMに名前のないイベントが残っていないか、生成されたJSX型に onundefined が含まれていないかをチェックし、検出された場合はビルドを失敗させます。この検証により、問題の再発を防ぐ仕組みが整いました。

まとめ

本PRは、Custom Elements Manifestの解析プロセスにフィルタリング段階を追加することで、StencilJSとの型互換性を確立しました。名前のないイベントエントリを除外し、標準DOMイベントのサポートを明示的に有効化することで、25個のコンポーネントにわたる型定義の問題が解消され、StencilプロジェクトでWeb Awesomeを使用する際の開発体験が向上します。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
4回 (改善を経て承認)
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「総論→各論→結論」の構成が記事全体で明確に適用されています。リード文、背景、技術詳細、設計判断、まとめの各要素が適切に配置されており、非常に分かりやすい構成です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトやGitHubのIssueリンク記法がガイドラインに沿って正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Custom Elements ManifestやStencilJSに関する専門的な内容であり、対象読者であるエンジニアに適した技術レベルと表現で書かれています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論で構成され、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られています。1段落1トピックが徹底されており、可読性が高いです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されている2つのコードブロックは、提供されたDiffの内容と完全に一致しており、変更点を正確に反映しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

Custom Elements Manifest, JSDoc, packageLinkPhaseなど、関連する技術用語が正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

プラグインによるイベントのフィルタリングや、設定変更による標準DOMイベントの有効化など、技術的な変更に関する説明は正確で論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(問題の原因、影響範囲、解決策、検証ステップの追加など)は、PRのDescriptionやDiffの内容によって裏付けられており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2026)、Issue番号(#1919)、影響を受けるコンポーネント数(25個)など、数値や固有名詞はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPRの技術的な核心を的確に表現しており、PR全体の目的とも整合性が取れています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に記載のない外部知識(バージョンのサポート状況など)の追加はなく、提供された情報源に忠実です。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

記事内の時間表現はPRの文脈と一致しており、事実を正確に伝えています。