diff --git a/eslint.config.js b/eslint.config.js index 86dd5831..450038a5 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -102,6 +102,12 @@ export default [ '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/naming-convention': [ 'error', + { + selector: 'typeLike', + format: ['PascalCase'], + leadingUnderscore: 'forbid', + trailingUnderscore: 'forbid', + }, { selector: 'accessor', format: ['camelCase', 'PascalCase'], @@ -127,12 +133,6 @@ export default [ leadingUnderscore: 'forbid', trailingUnderscore: 'forbid', }, - { - selector: 'interface', - format: ['PascalCase'], - leadingUnderscore: 'forbid', - trailingUnderscore: 'forbid', - }, { selector: 'variable', format: ['camelCase', 'UPPER_CASE'], diff --git a/src/script/Background.ts b/src/script/Background.ts index 66026a7e..a8816844 100644 --- a/src/script/Background.ts +++ b/src/script/Background.ts @@ -5,6 +5,47 @@ import Translation from '@APF/Translation'; import WebConfig from '@APF/WebConfig'; import { formatNumber } from '@APF/lib/helper'; import Logger from '@APF/lib/Logger'; +import type { Summary } from '@APF/WebFilter'; + +export interface BackgroundData { + disabledTab?: boolean; +} + +export interface BackgroundStorage { + tabs?: { + [tabId: number]: TabStorageOptions; + }; +} + +export interface Message { + advanced?: boolean; + backgroundData?: boolean; + counter?: number; + deep?: boolean; + destination: string; + disabled?: boolean; + enableTab?: boolean; + forceUpdate?: boolean; + getStatus?: boolean; + globalVariable?: string; + iframe?: boolean; + popup?: boolean; + source: string; + status?: number; + summary?: Summary; + tabId?: number; + updateContextMenus?: boolean; + urlUpdate?: string; +} + +export interface TabStorageOptions { + counters?: { number?: number }; + disabled?: boolean; + disabledOnce?: number; // NOT_SET: 0, DISABLED: 1, WILL_DISABLE: 2 + id?: number; + registeredAt?: number; + status?: number; +} export default class Background { //#region Class reference helpers diff --git a/src/script/BookmarkletFilter.ts b/src/script/BookmarkletFilter.ts index c9196cd0..a1057e29 100644 --- a/src/script/BookmarkletFilter.ts +++ b/src/script/BookmarkletFilter.ts @@ -4,6 +4,8 @@ import Domain from '@APF/Domain'; import Filter from '@APF/lib/Filter'; import Page from '@APF/Page'; import WebConfig from '@APF/WebConfig'; +import type { BackgroundData, Message } from '@APF/Background'; +import type { Statistics } from '@APF/WebFilter'; export default class BookmarkletFilter extends Filter { buildMessage: (destination: string, data?: object) => Message; // Bookmarklet: Not used - Needed to match signature of WebFilter diff --git a/src/script/DataMigration.ts b/src/script/DataMigration.ts index c3571708..23f762ea 100644 --- a/src/script/DataMigration.ts +++ b/src/script/DataMigration.ts @@ -1,6 +1,14 @@ import Constants from '@APF/lib/Constants'; import { booleanToNumber, getVersion, isVersionOlder } from '@APF/lib/helper'; import WebConfig from '@APF/WebConfig'; +import type { WordOptions } from '@APF/lib/Word'; + +export interface Migration { + async?: boolean; + name: string; + runOnImport: boolean; + version: string; +} export default class DataMigration { cfg: WebConfig; @@ -91,7 +99,7 @@ export default class DataMigration { // This will look at the version (from before the update) and perform data migrations if necessary async byVersion(oldVersion: string) { - const version = getVersion(oldVersion) as Version; + const version = getVersion(oldVersion); let migrated = false; for (const migration of (this.constructor as typeof DataMigration).migrations) { if (isVersionOlder(version, getVersion(migration.version))) { diff --git a/src/script/Domain.ts b/src/script/Domain.ts index 9cb2a369..2e753907 100644 --- a/src/script/Domain.ts +++ b/src/script/Domain.ts @@ -1,6 +1,16 @@ import Constants from '@APF/lib/Constants'; import type WebConfig from '@APF/WebConfig'; +export interface DomainCfg { + adv?: boolean; + deep?: boolean; + disabled?: boolean; + enabled?: boolean; + framesOff?: boolean; + framesOn?: boolean; + wordlist?: number; +} + export default class Domain { advanced: boolean; cfg: DomainCfg; diff --git a/src/script/Environment.ts b/src/script/Environment.ts new file mode 100644 index 00000000..ceac9968 --- /dev/null +++ b/src/script/Environment.ts @@ -0,0 +1,305 @@ +import type WebConfig from '@APF/WebConfig'; + +export interface BrowserInfo { + browser: + | typeof Environment.BROWSER_CHROME + | typeof Environment.BROWSER_SAFARI + | typeof Environment.BROWSER_FIREFOX + | typeof Environment.BROWSER_EDGE + | typeof Environment.BROWSER_OPERA + | typeof Environment.BROWSER_UNKNOWN; + device: typeof Environment.DEVICE_DESKTOP | typeof Environment.DEVICE_TABLET | typeof Environment.DEVICE_PHONE; + os: + | typeof Environment.OS_ANDROID + | typeof Environment.OS_CHROMEOS + | typeof Environment.OS_IOS + | typeof Environment.OS_LINUX + | typeof Environment.OS_MACOS + | typeof Environment.OS_UNKNOWN + | typeof Environment.OS_WINDOWS; +} + +type BaseTarget = + | typeof Environment.BUILD_TARGET_BOOKMARKLET + | typeof Environment.BUILD_TARGET_CHROME + | typeof Environment.BUILD_TARGET_FIREFOX; + +// open union: allows extra literal strings later (subclasses) +type AnyTarget = BaseTarget | (string & {}); + +export interface BuildInfo { + config: Partial; + manifestVersion: number; + release: boolean; + target: AnyTarget; + version: string; +} + +type UAData = + | { + brands?: Array<{ brand: string; version: string }>; + mobile?: boolean; + platform?: string; + } + | undefined; + +// __BUILD__ is injected by webpack from ROOT/.build.json +/* eslint-disable-next-line @typescript-eslint/naming-convention */ +declare const __BUILD__: BuildInfo | undefined; +const BUILD_DEFAULTS: BuildInfo = { config: {}, manifestVersion: 3, release: true, target: 'chrome', version: '1.0.0' }; + +export default class Environment { + // Static constants + static readonly BROWSER_CHROME = 'chrome' as const; + static readonly BROWSER_EDGE = 'edge' as const; + static readonly BROWSER_FIREFOX = 'firefox' as const; + static readonly BROWSER_OPERA = 'opera' as const; + static readonly BROWSER_SAFARI = 'safari' as const; + static readonly BROWSER_UNKNOWN = 'unknown' as const; + static readonly BUILD_TARGET_BOOKMARKLET = 'bookmarklet' as const; + static readonly BUILD_TARGET_CHROME = 'chrome' as const; + static readonly BUILD_TARGET_FIREFOX = 'firefox' as const; + static readonly DEVICE_DESKTOP = 'desktop' as const; + static readonly DEVICE_PHONE = 'phone' as const; + static readonly DEVICE_TABLET = 'tablet' as const; + static readonly OS_ANDROID = 'android' as const; + static readonly OS_CHROMEOS = 'chromeos' as const; + static readonly OS_IOS = 'ios' as const; + static readonly OS_LINUX = 'linux' as const; + static readonly OS_MACOS = 'macos' as const; + static readonly OS_UNKNOWN = 'unknown' as const; + static readonly OS_WINDOWS = 'windows' as const; + + // Static environment values - computed once and cached + private static readonly _BUILD_INFO: Readonly = Object.freeze( + typeof __BUILD__ === 'undefined' ? BUILD_DEFAULTS : __BUILD__, + ); + private static readonly _BROWSER_INFO = Environment._computeBrowserInfoSafe(); + + // Static getters for browser info + static get browser(): BrowserInfo['browser'] { + return this._BROWSER_INFO.browser; + } + static get os(): BrowserInfo['os'] { + return this._BROWSER_INFO.os; + } + static get device(): BrowserInfo['device'] { + return this._BROWSER_INFO.device; + } + + // Static getters for build info + static get buildTarget(): BuildInfo['target'] { + return this._BUILD_INFO.target; + } + + static get manifestVersion(): BuildInfo['manifestVersion'] { + return this._BUILD_INFO.manifestVersion; + } + + static get release(): BuildInfo['release'] { + return this._BUILD_INFO.release; + } + + static get version(): BuildInfo['version'] { + return this._BUILD_INFO.version; + } + + static get config(): BuildInfo['config'] { + return this._BUILD_INFO.config; + } + + // Browser target static helpers + static get isChromeTarget() { + return this.buildTarget === this.BUILD_TARGET_CHROME; + } + + static get isFirefoxTarget() { + return this.buildTarget === this.BUILD_TARGET_FIREFOX; + } + + static get isBookmarkletTarget() { + return this.buildTarget === this.BUILD_TARGET_BOOKMARKLET; + } + + // Build environment static helpers + static get isProduction() { + return this.release; + } + + static get isDevelopment() { + return !this.isProduction; + } + + // Device type static helpers + static get isDesktop() { + return this.device === this.DEVICE_DESKTOP; + } + + static get isTablet() { + return this.device === this.DEVICE_TABLET; + } + + static get isPhone() { + return this.device === this.DEVICE_PHONE; + } + + static get isMobile() { + return this.isTablet || this.isPhone; + } + + // Browser static helpers + static get isChrome() { + return this.browser === this.BROWSER_CHROME; + } + + static get isFirefox() { + return this.browser === this.BROWSER_FIREFOX; + } + + static get isSafari() { + return this.browser === this.BROWSER_SAFARI; + } + + static get isEdge() { + return this.browser === this.BROWSER_EDGE; + } + + static get isOpera() { + return this.browser === this.BROWSER_OPERA; + } + + // OS static helpers + static get isWindows() { + return this.os === this.OS_WINDOWS; + } + + static get isMacOS() { + return this.os === this.OS_MACOS; + } + + static get isLinux() { + return this.os === this.OS_LINUX; + } + + static get isAndroid() { + return this.os === this.OS_ANDROID; + } + + static get isIOS() { + return this.os === this.OS_IOS; + } + + static get isChromeOS() { + return this.os === this.OS_CHROMEOS; + } + + // Manifest version static helpers + static get isManifestV2() { + return this.manifestVersion === 2; + } + + static get isManifestV3() { + return this.manifestVersion === 3; + } + + private static _computeBrowserInfoSafe(): BrowserInfo { + const unknown: BrowserInfo = { browser: this.BROWSER_UNKNOWN, os: this.OS_UNKNOWN, device: this.DEVICE_DESKTOP }; + try { + if (typeof navigator === 'undefined') { + return unknown; + } + return this._computeBrowserInfo(); + } catch { + return unknown; + } + } + + private static _computeBrowserInfo(): BrowserInfo { + const ua = navigator.userAgent || ''; + const uaData = (navigator as any).userAgentData as UAData; + + // iPadOS heuristic (handles Safari reporting MacIntel) + const isiPadByPlatform = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1; + const isiPadByUA = /\biPad\b/i.test(ua); + const isiPadByCH = (uaData?.platform === 'macOS' || uaData?.platform === 'Mac OS') && navigator.maxTouchPoints > 1; + const isiPadHeuristic = isiPadByPlatform || isiPadByUA || isiPadByCH; + + // OS detection + let os: BrowserInfo['os'] = this.OS_UNKNOWN; + if (/Windows/i.test(ua)) os = this.OS_WINDOWS; + else if (/Android/i.test(ua)) os = this.OS_ANDROID; + else if (/iPhone|iPod/i.test(ua)) os = this.OS_IOS; + else if (isiPadHeuristic) os = this.OS_IOS; + else if (/Mac/i.test(ua)) os = this.OS_MACOS; + else if (/CrOS/i.test(ua)) os = this.OS_CHROMEOS; + else if (/Linux/i.test(ua)) os = this.OS_LINUX; + + // Browser detection (filter "Not/A Brand") + const brands = (uaData?.brands ?? []).map((b) => b.brand.toLowerCase()).filter((b) => !/not.?a.?brand/i.test(b)); + const hasBrand = (name: string) => brands.some((b) => b.includes(name)); + + let browser: BrowserInfo['browser'] = this.BROWSER_UNKNOWN; + if (hasBrand('edge') || /Edg(?:e|A|iOS)?\//i.test(ua)) { + browser = this.BROWSER_EDGE; + } else if (hasBrand('opera') || /OPR\/|Opera/i.test(ua)) { + browser = this.BROWSER_OPERA; + } else if (hasBrand('chrome') || /Chrome\/|CriOS\//i.test(ua)) { + if (!/OPR\/|Edg(?:e|A|iOS)?\//i.test(ua)) browser = this.BROWSER_CHROME; + } else if (/FxiOS\/|Firefox\//i.test(ua)) { + browser = this.BROWSER_FIREFOX; + } else if (hasBrand('safari') || (/Safari\//i.test(ua) && !/Chrome|Chromium|CriOS|FxiOS|Edg|OPR/i.test(ua))) { + browser = this.BROWSER_SAFARI; + } + + // Device type + const chMobile = uaData?.mobile; + const isTouch = + (typeof matchMedia === 'function' && + (() => { + try { + return matchMedia('(pointer: coarse)').matches; + } catch { + return false; + } + })()) || + (typeof navigator.maxTouchPoints === 'number' && navigator.maxTouchPoints > 1); + + const viewportShortSide = + typeof window !== 'undefined' ? Math.min(window.innerWidth || 0, window.innerHeight || 0) : 0; + + let device: BrowserInfo['device'] = this.DEVICE_DESKTOP; + + if (os === this.OS_IOS) { + device = isiPadHeuristic ? this.DEVICE_TABLET : this.DEVICE_PHONE; + } else if (os === this.OS_ANDROID) { + const uaHasMobile = /\bMobile\b/i.test(ua); + const uaHasTabletWord = /\bTablet\b|\bPad\b/i.test(ua); + const androidIsTablet = uaHasTabletWord || !uaHasMobile; + + if (chMobile === false) { + device = this.DEVICE_TABLET; // UA-CH says "not mobile" → treat as tablet + } else { + device = androidIsTablet ? this.DEVICE_TABLET : this.DEVICE_PHONE; + } + } else { + // Non–Android/iOS: prefer desktop; use touch + viewport as a hint + if (isTouch) { + if (viewportShortSide > 0 && viewportShortSide < 600) { + device = this.DEVICE_PHONE; + } else if (viewportShortSide >= 600) { + device = this.DEVICE_TABLET; + } else { + device = this.DEVICE_DESKTOP; + } + } else { + device = this.DEVICE_DESKTOP; + } + } + + return { browser, os, device }; + } + + constructor() { + throw new Error('Environment is a static class and cannot be instantiated'); + } +} diff --git a/src/script/OptionPage.ts b/src/script/OptionPage.ts index ffae7a1c..79b772e3 100644 --- a/src/script/OptionPage.ts +++ b/src/script/OptionPage.ts @@ -1,7 +1,7 @@ import Constants from '@APF/lib/Constants'; import WebConfig from '@APF/WebConfig'; import Filter from '@APF/lib/Filter'; -import Domain from '@APF/Domain'; +import Domain, { type DomainCfg } from '@APF/Domain'; import OptionAuth from '@APF/OptionAuth'; import DataMigration from '@APF/DataMigration'; import Bookmarklet from '@APF/bookmarklet'; @@ -21,6 +21,16 @@ import { timeForFileName, upperCaseFirst, } from '@APF/lib/helper'; +import type { Message } from '@APF/Background'; +import type { Statistics } from '@APF/WebFilter'; +import type { WordOptions } from '@APF/lib/Word'; + +export interface ConfirmModalSettings { + backup?: boolean; + content?: string; + title?: string; + titleClass?: string; +} const logger = new Logger('OptionPage'); @@ -1658,7 +1668,7 @@ export default class OptionPage { const wordsSelect = document.getElementById('wordList') as HTMLSelectElement; // Workaround for remove filter method - if (this.filter.cfg.filterWordList && this.filter.cfg.filterMethod === 2) { + if (this.filter.cfg.filterWordList && this.filter.cfg.filterMethod === this.Class.Constants.FILTER_METHODS.REMOVE) { wordlistFilter = new this.Class.Filter(); // Works because we are only changing a native value (filterMethod: number) wordlistFilter.cfg = new this.Class.Config(Object.assign({}, this.cfg, { filterMethod: 0 })); @@ -2177,7 +2187,7 @@ export default class OptionPage { setHelpVersion() { const helpVersion = document.getElementById('helpVersion') as HTMLAnchorElement; - helpVersion.textContent = this.cfg._buildInfo.version; + helpVersion.textContent = this.cfg._env.version; } setupEventListeners() { diff --git a/src/script/Popup.ts b/src/script/Popup.ts index c7022920..0f0aa2cb 100644 --- a/src/script/Popup.ts +++ b/src/script/Popup.ts @@ -5,6 +5,9 @@ import Page from '@APF/Page'; import Logger from '@APF/lib/Logger'; import Translation from '@APF/Translation'; import { sendMessageWithRetry } from '@APF/lib/helper'; +import type { Summary } from '@APF/WebFilter'; +import type { BackgroundData, Message } from '@APF/Background'; + const logger = new Logger('Popup'); export default class Popup { @@ -359,10 +362,8 @@ export default class Popup { return ( !this.domain.hostname || this.Class.Page.disabledProtocols.test(this.url.protocol) || - (this.cfg._buildInfo.target == this.Class.Constants.BUILD_TARGET_CHROME && - this.Class.Page.disabledChromePages.includes(this.domain.hostname)) || - (this.cfg._buildInfo.target == this.Class.Constants.BUILD_TARGET_FIREFOX && - this.Class.Page.disabledFirefoxPages.includes(this.domain.hostname)) + (this.cfg._env.isChromeTarget && this.Class.Page.disabledChromePages.includes(this.domain.hostname)) || + (this.cfg._env.isFirefoxTarget && this.Class.Page.disabledFirefoxPages.includes(this.domain.hostname)) ); } diff --git a/src/script/WebConfig.ts b/src/script/WebConfig.ts index d57a5fd4..5e8b9414 100644 --- a/src/script/WebConfig.ts +++ b/src/script/WebConfig.ts @@ -3,16 +3,14 @@ import { prettyPrintArray, removeFromArray, sortObjectKeys, stringArray } from ' import Logger from '@APF/lib/Logger'; import Translation from '@APF/Translation'; import Constants from '@APF/lib/Constants'; +import Environment from '@APF/Environment'; +import type { DomainCfg } from '@APF/Domain'; -// __BUILD__ is injected by webpack from ROOT/.build.json -/* eslint-disable-next-line @typescript-eslint/naming-convention */ -declare const __BUILD__: BuildInfo; -const BUILD_DEFAULTS: BuildInfo = { config: {}, manifestVersion: 3, release: true, target: 'chrome', version: '1.0.0' }; const logger = new Logger('WebConfig'); export default class WebConfig extends Config { - _buildInfo: BuildInfo; _defaultsLoaded: string[]; + _env: typeof Environment; _lastSplitKeys: { [key: string]: number }; collectStats: boolean; contextMenu: boolean; @@ -30,6 +28,9 @@ export default class WebConfig extends Config { static get Constants() { return Constants; } + static get Environment() { + return Environment; + } get Class() { return this.constructor as typeof WebConfig; } @@ -39,7 +40,6 @@ export default class WebConfig extends Config { return logger; } - static readonly BUILD = typeof __BUILD__ == 'undefined' ? BUILD_DEFAULTS : __BUILD__; static readonly _webDefaults = { collectStats: true, contextMenu: true, @@ -335,7 +335,7 @@ export default class WebConfig extends Config { // Apply the Config defaults super(config); - this._buildInfo = this.Class.BUILD; + this._env = this.Class.Environment; this.log.setLevel(this.loggingLevel); @@ -361,12 +361,7 @@ export default class WebConfig extends Config { } localizeDefaults() { - if ( - this._buildInfo.target === this.Class.Constants.BUILD_TARGET_BOOKMARKLET || - !this._defaultsLoaded || - !this._defaultsLoaded.length - ) - return; + if (this._env.isBookmarkletTarget || !this._defaultsLoaded || !this._defaultsLoaded.length) return; const translation = new Translation('common', this.language); diff --git a/src/script/WebFilter.ts b/src/script/WebFilter.ts index 452c8455..27f4e6c8 100644 --- a/src/script/WebFilter.ts +++ b/src/script/WebFilter.ts @@ -6,6 +6,29 @@ import Page from '@APF/Page'; import WebConfig from '@APF/WebConfig'; import Logger from '@APF/lib/Logger'; import type Word from '@APF/lib/Word'; +import type { BackgroundData, Message } from '@APF/Background'; + +export interface Statistics { + startedAt?: number; + words: WordStatistics; +} + +export interface Summary { + [word: string]: { + filtered: string; + count: number; + }; +} + +export interface WordStatistic { + text: number; + total?: number; +} + +export interface WordStatistics { + [word: string]: WordStatistic; +} + const logger = new Logger('WebFilter'); export default class WebFilter extends Filter { diff --git a/src/script/entry/bookmarklet.ts b/src/script/entry/bookmarklet.ts index ae49961f..444dadaf 100644 --- a/src/script/entry/bookmarklet.ts +++ b/src/script/entry/bookmarklet.ts @@ -7,7 +7,7 @@ import BookmarkletFilter from '@APF/BookmarkletFilter'; const config = WebConfig._defaults as WebConfig; /* @preserve - End User Config */ -console.log(`[APF Bookmarklet] Activated (version ${WebConfig.BUILD.version})`); +console.log(`[APF Bookmarklet] Activated (version ${WebConfig.Environment.version})`); if (typeof window !== 'undefined' && !(window).apfBookmarklet) { (window).apfBookmarklet = true; console.log('[APF Bookmarklet] Running'); diff --git a/src/script/lib/Config.ts b/src/script/lib/Config.ts index 492f5627..d616b3d1 100644 --- a/src/script/lib/Config.ts +++ b/src/script/lib/Config.ts @@ -1,4 +1,5 @@ import Constants from './Constants'; +import type { WordOptions } from './Word'; export default class Config { censorCharacter: string; diff --git a/src/script/lib/Constants.ts b/src/script/lib/Constants.ts index 75ecdd95..480ab408 100644 --- a/src/script/lib/Constants.ts +++ b/src/script/lib/Constants.ts @@ -4,9 +4,6 @@ import { upperCaseFirst } from './helper'; export default class Constants { // Named Constants static readonly ALL_WORDS_WORDLIST_ID = 0; - static readonly BUILD_TARGET_BOOKMARKLET = 'bookmarklet'; - static readonly BUILD_TARGET_CHROME = 'chrome'; - static readonly BUILD_TARGET_FIREFOX = 'firefox'; static readonly DOMAIN_MODES = { NORMAL: 0, ADVANCED: 1, DEEP: 2 }; static readonly FALSE = 0; static readonly FILTER_METHODS = { CENSOR: 0, SUBSTITUTE: 1, REMOVE: 2, OFF: 3 }; diff --git a/src/script/lib/Filter.ts b/src/script/lib/Filter.ts index 322a6895..c4e1848b 100644 --- a/src/script/lib/Filter.ts +++ b/src/script/lib/Filter.ts @@ -1,9 +1,15 @@ import Constants from './Constants'; -import Word from './Word'; +import Word, { type WordOptions } from './Word'; import Wordlist from './Wordlist'; import Config from './Config'; import { randomArrayElement } from './helper'; +export interface ReplaceTextResult { + filtered: string; + modified: boolean; + original: string; +} + export default class Filter { allowlist: string[]; cfg: Config; diff --git a/src/script/lib/Word.ts b/src/script/lib/Word.ts index edc8be52..e381e21c 100644 --- a/src/script/lib/Word.ts +++ b/src/script/lib/Word.ts @@ -1,6 +1,16 @@ import Constants from './Constants'; import Config from './Config'; +export interface WordOptions { + _filterMethod?: number; // This should not be stored in the config. Only there for new Word + case?: number; + lists?: number[]; + matchMethod: number; + repeat: number; + separators?: number; + sub: string; +} + export default class Word { _filterMethod: number; case?: number; diff --git a/src/script/lib/globals.d.ts b/src/script/lib/globals.d.ts deleted file mode 100644 index 8ad18e0b..00000000 --- a/src/script/lib/globals.d.ts +++ /dev/null @@ -1,114 +0,0 @@ -interface BackgroundData { - disabledTab?: boolean; -} - -interface BackgroundStorage { - tabs?: { - [tabId: number]: TabStorageOptions; - }; -} - -interface BuildInfo { - config: any; - manifestVersion: number; - release: boolean; - target: string; - version: string; -} - -interface ConfirmModalSettings { - backup?: boolean; - content?: string; - title?: string; - titleClass?: string; -} - -interface DomainCfg { - adv?: boolean; - deep?: boolean; - disabled?: boolean; - enabled?: boolean; - framesOff?: boolean; - framesOn?: boolean; - wordlist?: number; -} - -interface Message { - advanced?: boolean; - backgroundData?: boolean; - counter?: number; - deep?: boolean; - destination: string; - disabled?: boolean; - enableTab?: boolean; - forceUpdate?: boolean; - getStatus?: boolean; - globalVariable?: string; - iframe?: boolean; - popup?: boolean; - source: string; - status?: number; - summary?: Summary; - tabId?: number; - updateContextMenus?: boolean; - urlUpdate?: string; -} - -interface Migration { - async?: boolean; - name: string; - runOnImport: boolean; - version: string; -} - -interface ReplaceTextResult { - filtered: string; - modified: boolean; - original: string; -} - -interface Statistics { - startedAt?: number; - words: WordStatistics; -} - -interface Summary { - [word: string]: { - filtered: string; - count: number; - }; -} - -interface TabStorageOptions { - counters?: { number?: number }; - disabled?: boolean; - disabledOnce?: number; // NOT_SET: 0, DISABLED: 1, WILL_DISABLE: 2 - id?: number; - registeredAt?: number; - status?: number; -} - -interface Version { - major: number; - minor: number; - patch: number; -} - -interface WordOptions { - _filterMethod?: number; // This should not be stored in the config. Only there for new Word - case?: number; - lists?: number[]; - matchMethod: number; - repeat: number; - separators?: number; - sub: string; -} - -interface WordStatistic { - text: number; - total?: number; -} - -interface WordStatistics { - [word: string]: WordStatistic; -} diff --git a/src/script/lib/helper.ts b/src/script/lib/helper.ts index 5a1718a6..34ecfc6e 100644 --- a/src/script/lib/helper.ts +++ b/src/script/lib/helper.ts @@ -1,5 +1,11 @@ import Constants from './Constants'; +export interface Version { + major: number; + minor: number; + patch: number; +} + export function booleanToNumber(value: boolean): number { return value ? Constants.TRUE : Constants.FALSE; } @@ -259,11 +265,11 @@ export function upperCaseFirst(str: string, lowerCaseRest: boolean = true): stri * @param fallbackResponse - Default response if all retries fail * @returns Promise that resolves with the response */ -export function sendMessageWithRetry( +export function sendMessageWithRetry( message: any, maxRetries: number = 3, - fallbackResponse?: tResponse, -): Promise { + fallbackResponse?: TResponse, +): Promise { return new Promise((resolve) => { let attempts = 0;