From 1ec17cd83e1b5299714436255b44dcabfd0aa545 Mon Sep 17 00:00:00 2001 From: Daniel Dada Date: Wed, 8 Oct 2025 11:09:16 +0300 Subject: [PATCH] chore: migrated to typescript --- .github/workflows/publish-extension.yml | 14 ++++- .gitignore | 4 +- background.js | 18 ------ manifest.json | 2 +- package-lock.json | 53 ++++++++++++++++- package.json | 10 +++- popup/popup.html | 3 +- src/background.ts | 20 +++++++ main.js => src/main.ts | 1 + popup/popup.js => src/popup/popup.ts | 1 + src/types.ts | 75 +++++++++++++++++++++++++ tsconfig.json | 30 ++++++++++ 12 files changed, 205 insertions(+), 26 deletions(-) delete mode 100644 background.js create mode 100644 src/background.ts rename main.js => src/main.ts (99%) rename popup/popup.js => src/popup/popup.ts (99%) create mode 100644 src/types.ts create mode 100644 tsconfig.json diff --git a/.github/workflows/publish-extension.yml b/.github/workflows/publish-extension.yml index cce6038..b6958c2 100644 --- a/.github/workflows/publish-extension.yml +++ b/.github/workflows/publish-extension.yml @@ -16,13 +16,25 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build extension + run: npm run build + - name: Set version from tag id: version run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT - name: Create zip package run: | - zip -r goose-highlighter.zip . -x '*.git*' 'node_modules/*' 'versioning.md' '.releaserc.json' 'package.json' 'package-lock.json' 'README.md' + zip -r goose-highlighter.zip . -x '*.git*' 'node_modules/*' 'src/*' 'versioning.md' '.releaserc.json' 'package.json' 'package-lock.json' 'README.md' 'tsconfig.json' 'eslint.config.mjs' - name: Install webstore upload CLI run: npm install -g chrome-webstore-upload-cli diff --git a/.gitignore b/.gitignore index b512c09..35ccbe5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -node_modules \ No newline at end of file +node_modules + +dist \ No newline at end of file diff --git a/background.js b/background.js deleted file mode 100644 index b602714..0000000 --- a/background.js +++ /dev/null @@ -1,18 +0,0 @@ -chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - if (changeInfo.status === 'complete' && /^https?:/.test(tab.url)) { - chrome.scripting.executeScript({ - target: { tabId }, - files: ['main.js'] - }).catch(err => { - console.warn('Injection failed:', err); - }); - } -}); - -chrome.runtime.onInstalled.addListener(() => { - chrome.storage.local.get(['exceptionsList'], (result) => { - if (!result.exceptionsList) { - chrome.storage.local.set({ exceptionsList: [] }); - } - }); -}); \ No newline at end of file diff --git a/manifest.json b/manifest.json index 7e99661..0b303f1 100644 --- a/manifest.json +++ b/manifest.json @@ -17,7 +17,7 @@ "default_icon": "icons/icon128.png" }, "background": { - "service_worker": "background.js" + "service_worker": "dist/background.js" }, "icons": { "48": "icons/icon48.png", diff --git a/package-lock.json b/package-lock.json index 76258ac..8eb47c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,11 @@ "@semantic-release/changelog": "^6.0.3", "@semantic-release/exec": "^7.1.0", "@semantic-release/git": "^10.0.1", + "@types/chrome": "^0.0.270", "eslint": "^9.30.0", "globals": "^16.2.0", - "semantic-release": "^24.2.5" + "semantic-release": "^24.2.5", + "typescript": "^5.6.0" } }, "node_modules/@babel/code-frame": { @@ -1213,6 +1215,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@types/chrome": { + "version": "0.0.270", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.270.tgz", + "integrity": "sha512-ADvkowV7YnJfycZZxL2brluZ6STGW+9oKG37B422UePf2PCXuFA/XdERI0T18wtuWPx0tmFeZqq6MOXVk1IC+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1220,6 +1233,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/filesystem": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", + "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", + "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", + "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -7624,6 +7661,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", diff --git a/package.json b/package.json index f7e87fa..5753006 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,17 @@ "@semantic-release/changelog": "^6.0.3", "@semantic-release/exec": "^7.1.0", "@semantic-release/git": "^10.0.1", + "@types/chrome": "^0.0.270", "eslint": "^9.30.0", "globals": "^16.2.0", - "semantic-release": "^24.2.5" + "semantic-release": "^24.2.5", + "typescript": "^5.6.0" }, "scripts": { - "prepare": "node scripts/update-manifest-version.js" + "build": "tsc", + "watch": "tsc --watch", + "clean": "rimraf dist", + "rebuild": "npm run clean && npm run build", + "prepare": "npm run build && node scripts/update-manifest-version.js" } } diff --git a/popup/popup.html b/popup/popup.html index 6bc1bba..b3f4a61 100644 --- a/popup/popup.html +++ b/popup/popup.html @@ -148,8 +148,7 @@ - - + \ No newline at end of file diff --git a/src/background.ts b/src/background.ts new file mode 100644 index 0000000..5dadf64 --- /dev/null +++ b/src/background.ts @@ -0,0 +1,20 @@ +// Handle tab updates to inject content script +chrome.tabs.onUpdated.addListener((tabId: number, changeInfo: chrome.tabs.TabChangeInfo, tab: chrome.tabs.Tab): void => { + if (changeInfo.status === 'complete' && tab.url && /^https?:/.test(tab.url)) { + chrome.scripting.executeScript({ + target: { tabId }, + files: ['dist/main.js'] + }).catch((err: unknown) => { + console.warn('Injection failed:', err); + }); + } +}); + +// Initialize storage on extension install +chrome.runtime.onInstalled.addListener((): void => { + chrome.storage.local.get(['exceptionsList'], (result: any) => { + if (!result.exceptionsList) { + chrome.storage.local.set({ exceptionsList: [] }); + } + }); +}); \ No newline at end of file diff --git a/main.js b/src/main.ts similarity index 99% rename from main.js rename to src/main.ts index d6d9b8d..af299c9 100644 --- a/main.js +++ b/src/main.ts @@ -1,3 +1,4 @@ +// @ts-nocheck let currentLists = []; let isGlobalHighlightEnabled = true; let exceptionsList = []; diff --git a/popup/popup.js b/src/popup/popup.ts similarity index 99% rename from popup/popup.js rename to src/popup/popup.ts index 14f1c1f..f25d08b 100644 --- a/popup/popup.js +++ b/src/popup/popup.ts @@ -1,3 +1,4 @@ +// @ts-nocheck const listSelect = document.getElementById('listSelect'); const listName = document.getElementById('listName'); const listBg = document.getElementById('listBg'); diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..4dcf082 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,75 @@ +// Type definitions for the Goose Highlighter extension + +export interface HighlightWord { + wordStr: string; + background: string; + foreground: string; + active: boolean; +} + +export interface HighlightList { + id: number; + name: string; + background: string; + foreground: string; + active: boolean; + words: HighlightWord[]; +} + +export interface StorageData { + lists: HighlightList[]; + globalHighlightEnabled: boolean; + matchCaseEnabled: boolean; + matchWholeEnabled: boolean; + exceptionsList: string[]; +} + +export interface ActiveWord { + text: string; + background: string; + foreground: string; +} + +export interface MessageData { + type: 'WORD_LIST_UPDATED' | 'GLOBAL_TOGGLE_UPDATED' | 'MATCH_OPTIONS_UPDATED' | 'EXCEPTIONS_LIST_UPDATED'; + enabled?: boolean; + matchCase?: boolean; + matchWhole?: boolean; +} + +export interface SectionStates { + [sectionName: string]: boolean; +} + +export interface ExportData { + lists: HighlightList[]; + exceptionsList: string[]; +} + +// DOM element selectors used in popup +export interface PopupElements { + listSelect: HTMLSelectElement; + listName: HTMLInputElement; + listBg: HTMLInputElement; + listFg: HTMLInputElement; + listActive: HTMLInputElement; + bulkPaste: HTMLTextAreaElement; + wordList: HTMLDivElement; + importInput: HTMLInputElement; + matchCase: HTMLInputElement; + matchWhole: HTMLInputElement; +} + +// Default storage values +export const DEFAULT_STORAGE: Partial = { + lists: [], + globalHighlightEnabled: true, + matchCaseEnabled: false, + matchWholeEnabled: false, + exceptionsList: [] +}; + +// Constants +export const WORD_ITEM_HEIGHT = 32; +export const DEBOUNCE_DELAY = 300; +export const SCROLL_THROTTLE = 16; // ~60fps \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..138a4e1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "lib": ["ES2022", "DOM"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "noEmitOnError": false, + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "exactOptionalPropertyTypes": false, + "types": ["chrome"] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file