-
Notifications
You must be signed in to change notification settings - Fork 0
Convert JavaScript to TypeScript for improved type safety and maintainability #4
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
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
6016ee2
Initial plan
Copilot 742d2b8
Convert JavaScript to TypeScript with build setup
Copilot 6fe13bb
Complete TypeScript conversion with cleanup and documentation
Copilot 4b18235
Replace magic numbers with named constants for default window dimensions
Copilot afe6dc8
Add GitHub Copilot setup workflow for development environment
Copilot 4c71c07
Enhance GitHub Copilot setup workflow with comprehensive validation a…
Copilot beb114b
Improve Copilot setup workflow with better error handling and validation
Copilot f8bcbb8
Fix copilot-setup-steps.yml to match official documentation specifica…
Copilot 1e05159
Add Devcontainer support for development environment
Copilot b197738
Update Node.js to v22 LTS and add Japanese comments to tsconfig.json
Copilot 579f75b
Remove Japanese comments from tsconfig.json for cleaner JSON format
Copilot 38c0e2d
Update src/background.ts
SIkebe c7636aa
Refactor: Move type definitions to a new types.ts file and update imp…
SIkebe 97d471c
Cleanup: Remove unnecessary comments from copilot-setup-steps.yml for…
SIkebe 39e30a9
Cleanup: Remove npm cache configuration from Copilot setup steps
SIkebe 3361cd5
Apply suggestions from code review
SIkebe f239cdf
Fix: Update import path for types and correct return type in getDispl…
SIkebe aea61ba
Refactor: Consolidate type definitions into shared-types.ts and updat…
SIkebe 6192d91
Enhance: Update watch script in package.json to preserve output and a…
SIkebe eb476f7
Enhance: Add GitHub Actions extension to VSCode customizations in dev…
SIkebe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| { | ||
| "name": "Split Translator Development", | ||
| "image": "mcr.microsoft.com/devcontainers/javascript-node:22-bookworm", | ||
| "features": { | ||
| "ghcr.io/devcontainers/features/github-cli:1": {} | ||
| }, | ||
| "postCreateCommand": "npm install", | ||
| "customizations": { | ||
| "vscode": { | ||
| "extensions": [ | ||
| "github.vscode-github-actions", | ||
| "ms-vscode.vscode-typescript-next" | ||
| ] | ||
| } | ||
| }, | ||
| "remoteUser": "node" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| name: "Copilot Setup Steps" | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| push: | ||
| paths: | ||
| - .github/workflows/copilot-setup-steps.yml | ||
| pull_request: | ||
| paths: | ||
| - .github/workflows/copilot-setup-steps.yml | ||
|
|
||
| jobs: | ||
| # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. | ||
| copilot-setup-steps: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "22" | ||
|
|
||
| - name: Install JavaScript dependencies | ||
| run: npm install | ||
|
|
||
| - name: Build TypeScript project | ||
| run: npm run build |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,16 @@ | ||
| // Background script (Service Worker) | ||
|
|
||
| /// <reference path="shared-types.ts" /> | ||
|
|
||
| // Constants | ||
| const OVERLAP_PIXELS = 8; // Compensate for window frame gaps | ||
| const MIN_WINDOW_WIDTH = 400; // Minimum window width in pixels | ||
| const MIN_WINDOW_HEIGHT = 300; // Minimum window height in pixels | ||
| const DEFAULT_WINDOW_WIDTH = 800; // Default window width when current window width is unavailable | ||
| const DEFAULT_WINDOW_HEIGHT = 600; // Default window height when current window height is unavailable | ||
|
|
||
| // Common error handler | ||
| function handleError(error, context) { | ||
| function handleError(error: Error, context: string): { success: false; error: string } { | ||
| console.error(`${context}:`, error); | ||
| return { | ||
| success: false, | ||
|
|
@@ -15,7 +19,7 @@ function handleError(error, context) { | |
| } | ||
|
|
||
| // Message listener | ||
| chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | ||
| chrome.runtime.onMessage.addListener((request: SplitAndTranslateMessage, sender, sendResponse) => { | ||
|
||
| if (request.action === 'splitAndTranslate') { | ||
| handleSplitAndTranslate(request.currentTab, request.targetLanguage) | ||
| .then(result => sendResponse(result)) | ||
|
|
@@ -25,7 +29,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | |
| }); | ||
|
|
||
| // Split view handling | ||
| async function handleSplitView(currentTab, targetLanguage) { | ||
| async function handleSplitView(currentTab: chrome.tabs.Tab, targetLanguage: string): Promise<{ success: true }> { | ||
| try { | ||
| console.log('Starting split view:', currentTab); | ||
|
|
||
|
|
@@ -44,8 +48,8 @@ async function handleSplitView(currentTab, targetLanguage) { | |
| 'file://', | ||
| ]; | ||
|
|
||
| if (UNSUPPORTED_PREFIXES.some(prefix => currentTab.url.startsWith(prefix)) || | ||
| currentTab.url.includes('translate.goog')) { | ||
| if (UNSUPPORTED_PREFIXES.some(prefix => currentTab.url!.startsWith(prefix)) || | ||
| currentTab.url!.includes('translate.goog')) { | ||
| throw new Error('This page type cannot be translated. Please try on a regular website.'); | ||
| } | ||
|
|
||
|
|
@@ -71,14 +75,14 @@ async function handleSplitView(currentTab, targetLanguage) { | |
| const rightWidth = halfWidth + OVERLAP_PIXELS; | ||
|
|
||
| // Calculate positions (use entire display) | ||
| const leftPosition = { | ||
| const leftPosition: WindowPosition = { | ||
| left: displayLeft, | ||
| top: displayTop, | ||
| width: leftWidth, | ||
| height: displayHeight | ||
| }; | ||
|
|
||
| const rightPosition = { | ||
| const rightPosition: WindowPosition = { | ||
| left: displayLeft + halfWidth - OVERLAP_PIXELS, | ||
| top: displayTop, | ||
| width: rightWidth, | ||
|
|
@@ -96,15 +100,19 @@ async function handleSplitView(currentTab, targetLanguage) { | |
| state: 'normal' | ||
| }); | ||
|
|
||
| if (!rightWindow || !rightWindow.tabs || !rightWindow.tabs[0]?.id || !rightWindow.id) { | ||
| throw new Error('Failed to create right window'); | ||
| } | ||
|
|
||
| // Resize left window | ||
| await chrome.windows.update(currentTab.windowId, { | ||
| ...leftPosition, | ||
| state: 'normal' | ||
| }); | ||
|
|
||
| // Save data | ||
| const splitViewData = { | ||
| originalTabId: currentTab.id, | ||
| const splitViewData: SplitViewData = { | ||
| originalTabId: currentTab.id!, | ||
| duplicatedTabId: rightWindow.tabs[0].id, | ||
| targetLanguage: targetLanguage, | ||
| originalWindowId: currentTab.windowId, | ||
|
|
@@ -122,12 +130,12 @@ async function handleSplitView(currentTab, targetLanguage) { | |
| } | ||
|
|
||
| // Execute split view and translation at once | ||
| async function handleSplitAndTranslate(currentTab, targetLanguage) { | ||
| async function handleSplitAndTranslate(currentTab: chrome.tabs.Tab, targetLanguage: string): Promise<{ success: true }> { | ||
| try { | ||
| console.log('Starting split view + translation:', currentTab); | ||
|
|
||
| // Prepare translation URL in advance (for parallel processing) | ||
| const translateUrl = `https://translate.google.com/translate?sl=auto&tl=${targetLanguage}&u=${encodeURIComponent(currentTab.url)}`; | ||
| const translateUrl = `https://translate.google.com/translate?sl=auto&tl=${targetLanguage}&u=${encodeURIComponent(currentTab.url!)}`; | ||
|
|
||
| // 1. Execute split view | ||
| await handleSplitView(currentTab, targetLanguage); | ||
|
|
@@ -148,7 +156,7 @@ async function handleSplitAndTranslate(currentTab, targetLanguage) { | |
| const currentUrl = rightTab.url; | ||
|
|
||
| // Do nothing if URL is already Google Translate page | ||
| if (currentUrl.includes('translate.google.com')) { | ||
| if (currentUrl && currentUrl.includes('translate.google.com')) { | ||
| console.log('Right tab is already a Google Translate page'); | ||
| return { success: true }; | ||
| } | ||
|
|
@@ -176,7 +184,7 @@ async function handleSplitAndTranslate(currentTab, targetLanguage) { | |
| } | ||
|
|
||
| // Get display information (helper function) | ||
| async function getDisplayInfo() { | ||
| async function getDisplayInfo(): Promise<chrome.system.display.DisplayUnitInfo[]> { | ||
| if (!chrome.system?.display) return []; | ||
|
|
||
| return new Promise((resolve) => { | ||
|
|
@@ -192,7 +200,7 @@ async function getDisplayInfo() { | |
| } | ||
|
|
||
| // Wait for tab to finish loading (helper function) | ||
| async function waitForTabReady(tabId, maxWaitTime = 3000) { | ||
| async function waitForTabReady(tabId: number, maxWaitTime: number = 3000): Promise<void> { | ||
| const startTime = Date.now(); | ||
| while (Date.now() - startTime < maxWaitTime) { | ||
| try { | ||
|
|
@@ -206,7 +214,7 @@ async function waitForTabReady(tabId, maxWaitTime = 3000) { | |
| } | ||
|
|
||
| // Helper function to enforce minimum dimensions | ||
| function enforceMinimumDimensions(bounds) { | ||
| function enforceMinimumDimensions(bounds: DisplayBounds): DisplayBounds { | ||
| return { | ||
| ...bounds, | ||
| width: Math.max(bounds.width, MIN_WINDOW_WIDTH), | ||
|
|
@@ -215,22 +223,22 @@ function enforceMinimumDimensions(bounds) { | |
| } | ||
|
|
||
| // Get display bounds (helper function) | ||
| function getDisplayBounds(displays, currentWindow) { | ||
| let bounds; | ||
| function getDisplayBounds(displays: any[], currentWindow: chrome.windows.Window): DisplayBounds { | ||
| let bounds: DisplayBounds; | ||
|
|
||
| if (!displays || !displays.length) { | ||
| console.warn('No display information available, using current window bounds'); | ||
| bounds = { | ||
| left: currentWindow.left, // Preserve current window position | ||
| top: currentWindow.top, // Preserve current window position | ||
| width: currentWindow.width, | ||
| height: currentWindow.height | ||
| left: currentWindow.left ?? 0, // Preserve current window position | ||
| top: currentWindow.top ?? 0, // Preserve current window position | ||
| width: currentWindow.width ?? DEFAULT_WINDOW_WIDTH, | ||
| height: currentWindow.height ?? DEFAULT_WINDOW_HEIGHT | ||
| }; | ||
| } else { | ||
| // Find the display to which the current window belongs | ||
| // Use window center point for accurate detection | ||
| const windowCenterX = currentWindow.left + (currentWindow.width / 2); | ||
| const windowCenterY = currentWindow.top + (currentWindow.height / 2); | ||
| const windowCenterX = (currentWindow.left ?? 0) + ((currentWindow.width ?? DEFAULT_WINDOW_WIDTH) / 2); | ||
| const windowCenterY = (currentWindow.top ?? 0) + ((currentWindow.height ?? DEFAULT_WINDOW_HEIGHT) / 2); | ||
|
|
||
| const display = displays.find(d => | ||
| windowCenterX >= d.workArea.left && | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.