-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: extract feature handlers #10
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
leochiu-a
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.
Overall, this is a well-structured refactoring that successfully extracts feature handlers into separate modules. The code is cleaner and more maintainable with proper separation of concerns.
Key improvements:
- Clear separation of concerns with individual handler modules
- Introduction of
GitHubFeatureinterface provides good abstraction - Settings management extracted into dedicated classes
- Better testability with modular design
Issues found:
- Critical: Potential memory leak from unobserved MutationObserver in mergeHandler (line 78)
- Medium: No error handling in showSettings callback (line 22)
- Minor: Hardcoded timeout values without constants (lines 19, 82, 87)
- Minor: Missing type exports in features.ts
| if (showSettings.isEnabled('merged')) { | ||
| onMerged(); | ||
| } else { | ||
| console.log('🚫 PR merge banner disabled in settings'); |
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.
Critical: Potential Memory Leak - Missing Observer Disconnect
When settings are disabled, the code returns early without disconnecting the observer that was created. While the outer observer.disconnect() at line 80 executes in this case, the issue is in the callback at lines 54-58 where the observer should disconnect but might not in the disabled case.
Actually, reviewing more carefully: the code looks correct here as observer.disconnect() is always called at line 80 regardless of the settings check. However, there's still a logic issue: if the merged state is NOT present after 100ms, the observer keeps running until the 10-second timeout.
Consider adding a flag to prevent multiple triggers:
let hasTriggered = false;
const observer = new MutationObserver((mutations) => {
if (hasTriggered) return;
// ... rest of logic
if (merged found) {
hasTriggered = true;
observer.disconnect();
}
});|
|
||
| isEnabled(setting: ShowSettingKey): boolean { | ||
| const key = STATE_KEY_MAP[setting]; | ||
| return this.stateProvider()[key]; |
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.
Medium: Missing Error Handling
The stateProvider() callback is called without error handling. If it throws, the entire feature will break.
Suggested fix:
isEnabled(setting: ShowSettingKey): boolean {
try {
const key = STATE_KEY_MAP[setting];
return this.stateProvider()[key];
} catch (error) {
console.error('Error getting settings state:', error);
return true; // Default to enabled
}
}| chrome.storage.local.get(['prApprovalTriggered', 'prApprovalTime'], (result) => { | ||
| if (result.prApprovalTriggered && result.prApprovalTime) { | ||
| const timeDiff = Date.now() - result.prApprovalTime; | ||
| if (timeDiff < 30000 && options.showSettings.isEnabled('approved')) { |
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.
Minor: Magic Number - Extract Timeout Constant
The 30000ms timeout is hardcoded and appears in multiple handlers. Extract to a shared constant:
// In constants.ts
export const PR_ACTION_TIMEOUT_MS = 30000;
// Then use:
if (timeDiff < PR_ACTION_TIMEOUT_MS && ...)Same issue in:
createHandler.ts:18approveHandler.ts:23
| } | ||
| observer.disconnect(); | ||
| } | ||
| }, 100); |
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.
Minor: Hardcoded Timeout Values
Extract magic numbers to named constants:
const MERGE_CHECK_DELAY_MS = 100;
const MERGE_DETECTION_TIMEOUT_MS = 10000;|
|
||
| interface MergeFeatureOptions { | ||
| showSettings: ShowSettings; | ||
| onMerged: () => void; |
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.
Minor: Consider Exporting Interface
For better reusability and type checking, consider exporting MergeFeatureOptions and other option interfaces:
export interface MergeFeatureOptions {
showSettings: ShowSettings;
onMerged: () => void;
}Same for CreationFeatureOptions, ApprovalFeatureOptions, and CloseFeatureOptions.
Summary
This PR refactors the content script architecture by extracting feature-specific handlers into separate modules, improving code organization, maintainability, and testability. The monolithic
EldenRingMergerclass has been replaced with a feature-based architecture using dedicated handler modules and a centralized settings management system.Key Changes
mergeHandler.ts,createHandler.ts,approveHandler.ts,closeHandler.ts)features.tswith aGitHubFeatureinterface and feature classes (MergeFeature,CreationFeature,ApprovalFeature,CloseFeature) for consistent lifecycle managementSettingsStorefor state management andShowSettingsfor feature-specific settings queriesEldenRingMergertoEldenRingOrchestratorto better reflect its coordinating roleShowSettingswith proper TypeScript typing and removed implicit any typesmergeHandler.test.tswith test coverage for merge detection logicType of Change
Test Plan
Manual Testing
Automated Testing
npm testto verifymergeHandler.test.tspassesBreaking Changes
None
Checklist