-
-
Notifications
You must be signed in to change notification settings - Fork 115
feat: Use source generator for event dispatch extensions #1758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
b9ffb2c to
dc2a16a
Compare
|
Cool. Think this is heading in a good direction. Would it make sense to read EventHandlers.cs from the generator and get all the html event names (e.g., Obviously, there needs to be the special-cases explicitly in the generator, or just in a partial handcoded type. Looking at the Blazor sources, they actually have "reader" types that explicitly show what types of parameters can be passed in, e.g., we can see that ChangeEventArgsReader.cs supports, |
|
Also, want to add, that if this works as is correctly, we can always add my suggestions as an issue for future improvements, and get this merged in. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a source generator to replace manually written event dispatch extension methods. The changes move from hand-coded event dispatch extensions to source-generated ones, which improves maintainability and consistency across the codebase.
- Introduces a new source generator for event dispatch extensions
- Removes manually written event dispatch extension files
- Updates existing extensions to use
partialclasses to work with the generated code - Fixes style inconsistencies and adds Task overloads for async operations
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/bunit.tests/EventDispatchExtensions/WheelEventDispatchExtensionsTest.cs | Fixed type reference from MouseEventDispatchExtensions to WheelEventDispatchExtensions |
| src/bunit/EventDispatchExtensions/TouchEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit/EventDispatchExtensions/ProgressEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit/EventDispatchExtensions/PointerEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit/EventDispatchExtensions/MouseEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit/EventDispatchExtensions/MediaEventDispatchExtensions.cs | Updated to fix style and add Task overloads |
| src/bunit/EventDispatchExtensions/KeyboardEventDispatchExtensions.cs | Changed to partial class and simplified methods to work with generator |
| src/bunit/EventDispatchExtensions/InputEventDispatchExtensions.cs | Changed to partial class and added Task overloads |
| src/bunit/EventDispatchExtensions/FocusEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit/EventDispatchExtensions/DragEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit/EventDispatchExtensions/DialogEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit/EventDispatchExtensions/ClipboardEventDispatchExtensions.cs | Removed entire file - functionality moved to source generator |
| src/bunit.generators.internal/bunit.generators.internal.csproj | Added packaging configuration for the analyzer |
| src/bunit.generators.internal/Blazor/EventDispatcherExtensionGenerator.cs | New source generator that creates event dispatch extension methods |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| var methodName = eventArgsType.Replace("EventArgs", ""); | ||
| var eventName = $"on{methodName.ToLowerInvariant()}"; |
Copilot
AI
Sep 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The event name generation using ToLowerInvariant() may not work correctly for all event types. For example, ClipboardEventArgs would generate onclipboard instead of the correct event names like oncopy, oncut, onpaste. This could lead to incorrect event binding.
| private static void GenerateGenericEventExtension(StringBuilder sourceBuilder, string eventArgsType) | ||
| { | ||
| var methodName = eventArgsType.Replace("EventArgs", ""); | ||
| var eventName = $"on{methodName.ToLowerInvariant()}"; | ||
| GenerateAsyncEventMethod(sourceBuilder, methodName, eventName, eventArgsType); | ||
| } |
Copilot
AI
Sep 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The generic event extension generation is overly simplistic and doesn't handle complex event types properly. EventArgs types like ClipboardEventArgs, DragEventArgs, and FocusEventArgs have multiple specific events (copy/cut/paste, drag/dragend/drop, focus/blur) that can't be mapped with this simple string replacement approach.
0d457ae to
1e8cbfd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
|
||
| return helperClassType.GetMethods() | ||
| .Where(x => x.GetParameters().FirstOrDefault()?.ParameterType == typeof(IElement)) | ||
| .Where(x => x.GetParameters().Skip(1).FirstOrDefault()?.ParameterType == typeof(TEventArgs)) |
Copilot
AI
Oct 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Consider extracting the magic number 1 into a named constant to improve readability and make the intent clearer (e.g., SKIP_FIRST_PARAMETER = 1).
|
@linkdotnet I trust you let me know when I should do a proper review. |
Yeah will notify you. Have some more local stuff and the in-laws over ;) have to balance that out a bit :) |
b6462f4 to
9762345
Compare
|
@egil I do feel that thing is in a good state. |
9762345 to
7aa3753
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 3 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
src/bunit.generators.internal/Blazor/EventDispatcherExtensionGenerator.cs
Outdated
Show resolved
Hide resolved
| var qualifiedEventArgsType = eventArgsType == "ErrorEventArgs" | ||
| ? "Microsoft.AspNetCore.Components.Web.ErrorEventArgs" | ||
| : eventArgsType; |
Copilot
AI
Oct 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard-coding the special case for ErrorEventArgs makes the code brittle. Consider creating a mapping dictionary or using reflection to determine the fully qualified type name for better maintainability.
b1667f2 to
a5e5934
Compare
| foreach (var word in WordBoundaries.OrderByDescending(w => w.Length)) | ||
| { | ||
| if (i + word.Length <= eventName.Length && | ||
| eventName.AsSpan(i, word.Length).Equals(word.AsSpan(), StringComparison.OrdinalIgnoreCase)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know CoPilot recommended this, but it seems super redundant. string comparison will do this for you if it makes any sense at all in terms of performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will revert htat, and maybe move this into a variable. Have anyway some doc changes coming up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well before we had a SubString which for sure does incur a new object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, the change itself does make sense but it is convoluted and i will refactor it
egil
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming all tests pass, this looks great.
809e357 to
5ca8821
Compare
5ca8821 to
894f15a
Compare
|
@egil Updated the docs and made a small refactoring. I would merge that bad boy in |
What we talked about today.
Moved a lot of the code to source code generators, with some changes to the current version:
this Task<IElement>overload for theasyncversionsKeyPress('c')andKeyPressAsync('c')).