From 61850fd6c22a66e781d51248f51456fff45796ef Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Tue, 19 Aug 2025 19:57:06 -0600 Subject: [PATCH 01/16] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(build):=20Move=20bu?= =?UTF-8?q?ild=20info=20to=20Environment=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 56 +++++++++++++++++++++++++++++++++ src/script/OptionPage.ts | 2 +- src/script/Popup.ts | 6 ++-- src/script/WebConfig.ts | 20 +++++------- src/script/entry/bookmarklet.ts | 3 +- src/script/lib/Constants.ts | 3 -- 6 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 src/script/Environment.ts diff --git a/src/script/Environment.ts b/src/script/Environment.ts new file mode 100644 index 00000000..f05d4b08 --- /dev/null +++ b/src/script/Environment.ts @@ -0,0 +1,56 @@ +// __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' }; + +export default class Environment { + buildTarget: string; + manifestVersion: number; + release: boolean; + version: string; + _buildInfo: BuildInfo; + + static readonly BUILD_INFO = typeof __BUILD__ == 'undefined' ? BUILD_DEFAULTS : __BUILD__; + static readonly BUILD_TARGET_BOOKMARKLET = 'bookmarklet'; + static readonly BUILD_TARGET_CHROME = 'chrome'; + static readonly BUILD_TARGET_FIREFOX = 'firefox'; + + static get version() { + return this.BUILD_INFO.version; + } + + // Class reference helpers - can be overridden in children classes + get Class() { + return this.constructor as typeof Environment; + } + + constructor() { + this._buildInfo = this.Class.BUILD_INFO; + this.buildTarget = this.Class.BUILD_INFO.target; + this.manifestVersion = this.Class.BUILD_INFO.manifestVersion; + this.release = this.Class.BUILD_INFO.release; + this.version = this.Class.BUILD_INFO.version; + } + + // Browser targets + get isChromeTarget(): boolean { + return this.buildTarget === this.Class.BUILD_TARGET_CHROME; + } + + get isFirefoxTarget(): boolean { + return this.buildTarget === this.Class.BUILD_TARGET_FIREFOX; + } + + get isBookmarkletTarget(): boolean { + return this.buildTarget === this.Class.BUILD_TARGET_BOOKMARKLET; + } + + // Builds + get isProduction(): boolean { + return this.release; + } + + get isDevelopment(): boolean { + return !this.isProduction; + } +} diff --git a/src/script/OptionPage.ts b/src/script/OptionPage.ts index ffae7a1c..73139e13 100644 --- a/src/script/OptionPage.ts +++ b/src/script/OptionPage.ts @@ -2177,7 +2177,7 @@ export default class OptionPage { setHelpVersion() { const helpVersion = document.getElementById('helpVersion') as HTMLAnchorElement; - helpVersion.textContent = this.cfg._buildInfo.version; + helpVersion.textContent = this.cfg._environment.version; } setupEventListeners() { diff --git a/src/script/Popup.ts b/src/script/Popup.ts index c7022920..acda88f2 100644 --- a/src/script/Popup.ts +++ b/src/script/Popup.ts @@ -359,10 +359,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._environment.isChromeTarget && this.Class.Page.disabledChromePages.includes(this.domain.hostname)) || + (this.cfg._environment.isFirefoxTarget && this.Class.Page.disabledFirefoxPages.includes(this.domain.hostname)) ); } diff --git a/src/script/WebConfig.ts b/src/script/WebConfig.ts index d57a5fd4..4e4c0ce8 100644 --- a/src/script/WebConfig.ts +++ b/src/script/WebConfig.ts @@ -3,16 +3,13 @@ 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'; -// __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[]; + _environment: Environment; _lastSplitKeys: { [key: string]: number }; collectStats: boolean; contextMenu: boolean; @@ -30,6 +27,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 +39,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 +334,7 @@ export default class WebConfig extends Config { // Apply the Config defaults super(config); - this._buildInfo = this.Class.BUILD; + this._environment = new this.Class.Environment(); this.log.setLevel(this.loggingLevel); @@ -361,12 +360,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._environment.isBookmarkletTarget || !this._defaultsLoaded || !this._defaultsLoaded.length) return; const translation = new Translation('common', this.language); diff --git a/src/script/entry/bookmarklet.ts b/src/script/entry/bookmarklet.ts index ae49961f..c790bcd1 100644 --- a/src/script/entry/bookmarklet.ts +++ b/src/script/entry/bookmarklet.ts @@ -1,13 +1,14 @@ /* eslint-disable no-console */ import WebConfig from '@APF/WebConfig'; import BookmarkletFilter from '@APF/BookmarkletFilter'; +import Environment from '@APF/Environment'; /* @preserve - Advanced Profanity Filter by Richard Frost (FrostCo) */ /* @preserve - Start User Config */ 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 ${Environment.version})`); if (typeof window !== 'undefined' && !(window).apfBookmarklet) { (window).apfBookmarklet = true; console.log('[APF Bookmarklet] Running'); 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 }; From 9e3609475f56d2107c871d8d2622e91e49a3a5d1 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Tue, 19 Aug 2025 22:12:26 -0600 Subject: [PATCH 02/16] =?UTF-8?q?=E2=9C=A8=20(build):=20Add=20runtime=20br?= =?UTF-8?q?owser=20details=20to=20Environment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 166 +++++++++++++++++++++++++++++++++++- src/script/lib/globals.d.ts | 8 -- 2 files changed, 163 insertions(+), 11 deletions(-) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index f05d4b08..6c00b176 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -1,3 +1,43 @@ +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; +} + +interface BuildInfo { + config: any; + manifestVersion: number; + release: boolean; + target: + | typeof Environment.BUILD_TARGET_BOOKMARKLET + | typeof Environment.BUILD_TARGET_CHROME + | typeof Environment.BUILD_TARGET_FIREFOX; + version: string; +} + +interface Navigator { + userAgentData?: UserAgentData; +} + +interface UserAgentData { + brands?: Array<{ brand: string; version: string }>; + mobile?: boolean; + platform?: string; +} + // __BUILD__ is injected by webpack from ROOT/.build.json /* eslint-disable-next-line @typescript-eslint/naming-convention */ declare const __BUILD__: BuildInfo; @@ -10,18 +50,138 @@ export default class Environment { version: string; _buildInfo: BuildInfo; + // Class reference helpers - can be overridden in children classes + get Class() { + return this.constructor as typeof Environment; + } + + // Static constants static readonly BUILD_INFO = typeof __BUILD__ == 'undefined' ? BUILD_DEFAULTS : __BUILD__; + static readonly BROWSER_CHROME = 'chrome'; + static readonly BROWSER_EDGE = 'edge'; + static readonly BROWSER_FIREFOX = 'firefox'; + static readonly BROWSER_OPERA = 'opera'; + static readonly BROWSER_SAFARI = 'safari'; + static readonly BROWSER_UNKNOWN = 'unknown'; static readonly BUILD_TARGET_BOOKMARKLET = 'bookmarklet'; static readonly BUILD_TARGET_CHROME = 'chrome'; static readonly BUILD_TARGET_FIREFOX = 'firefox'; + static readonly DEVICE_DESKTOP = 'desktop'; + static readonly DEVICE_PHONE = 'phone'; + static readonly DEVICE_TABLET = 'tablet'; + static readonly OS_ANDROID = 'android'; + static readonly OS_CHROMEOS = 'chromeos'; + static readonly OS_IOS = 'ios'; + static readonly OS_LINUX = 'linux'; + static readonly OS_MACOS = 'macos'; + static readonly OS_UNKNOWN = 'unknown'; + static readonly OS_WINDOWS = 'windows'; + + // Environment values + private static readonly _BROWSER_INFO = Environment._computeBrowserInfoSafe(); + static readonly browser = Environment._BROWSER_INFO.browser; + static readonly os = Environment._BROWSER_INFO.os; + static readonly device = Environment._BROWSER_INFO.device; static get version() { return this.BUILD_INFO.version; } - // Class reference helpers - can be overridden in children classes - get Class() { - return this.constructor as typeof Environment; + 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 Navigator).userAgentData; + + // 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() { diff --git a/src/script/lib/globals.d.ts b/src/script/lib/globals.d.ts index 8ad18e0b..97958c08 100644 --- a/src/script/lib/globals.d.ts +++ b/src/script/lib/globals.d.ts @@ -8,14 +8,6 @@ interface BackgroundStorage { }; } -interface BuildInfo { - config: any; - manifestVersion: number; - release: boolean; - target: string; - version: string; -} - interface ConfirmModalSettings { backup?: boolean; content?: string; From 7509daeba41b15c3e4121a9e2d90c9e083cd49b9 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:35:56 -0600 Subject: [PATCH 03/16] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20(dev):=20Migrate?= =?UTF-8?q?=20from=20global=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Background.ts | 41 ++++++++++++ src/script/BookmarkletFilter.ts | 2 + src/script/DataMigration.ts | 10 ++- src/script/Domain.ts | 10 +++ src/script/OptionPage.ts | 12 +++- src/script/Popup.ts | 3 + src/script/WebConfig.ts | 1 + src/script/WebFilter.ts | 23 +++++++ src/script/lib/Config.ts | 1 + src/script/lib/Filter.ts | 8 ++- src/script/lib/Word.ts | 10 +++ src/script/lib/globals.d.ts | 106 -------------------------------- src/script/lib/helper.ts | 6 ++ 13 files changed, 124 insertions(+), 109 deletions(-) delete mode 100644 src/script/lib/globals.d.ts diff --git a/src/script/Background.ts b/src/script/Background.ts index 66026a7e..9a45f8fb 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; +} + +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; +} + +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..0c39be7e 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'; + +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/OptionPage.ts b/src/script/OptionPage.ts index 73139e13..27297b34 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'; + +interface ConfirmModalSettings { + backup?: boolean; + content?: string; + title?: string; + titleClass?: string; +} const logger = new Logger('OptionPage'); diff --git a/src/script/Popup.ts b/src/script/Popup.ts index acda88f2..03bc6bfd 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 { diff --git a/src/script/WebConfig.ts b/src/script/WebConfig.ts index 4e4c0ce8..cd0294e1 100644 --- a/src/script/WebConfig.ts +++ b/src/script/WebConfig.ts @@ -4,6 +4,7 @@ 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'; const logger = new Logger('WebConfig'); diff --git a/src/script/WebFilter.ts b/src/script/WebFilter.ts index 452c8455..66ac0c8d 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; + }; +} + +interface WordStatistic { + text: number; + total?: number; +} + +interface WordStatistics { + [word: string]: WordStatistic; +} + const logger = new Logger('WebFilter'); export default class WebFilter extends Filter { 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/Filter.ts b/src/script/lib/Filter.ts index 322a6895..258c66d9 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'; +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 97958c08..00000000 --- a/src/script/lib/globals.d.ts +++ /dev/null @@ -1,106 +0,0 @@ -interface BackgroundData { - disabledTab?: boolean; -} - -interface BackgroundStorage { - tabs?: { - [tabId: number]: TabStorageOptions; - }; -} - -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..be504e4b 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; } From b5b32e5ee3ae63447b6600ab3188c8c1a6433d7b Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:00 -0600 Subject: [PATCH 04/16] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(build):=20Make=20En?= =?UTF-8?q?vironment=20a=20static-only=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 165 +++++++++++++++++++++++++++----------- src/script/WebConfig.ts | 4 +- 2 files changed, 122 insertions(+), 47 deletions(-) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index 6c00b176..7be6ab2b 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -1,3 +1,5 @@ +import type WebConfig from '@APF/WebConfig'; + interface BrowserInfo { browser: | typeof Environment.BROWSER_CHROME @@ -18,7 +20,7 @@ interface BrowserInfo { } interface BuildInfo { - config: any; + config: Partial; manifestVersion: number; release: boolean; target: @@ -44,19 +46,7 @@ declare const __BUILD__: BuildInfo; const BUILD_DEFAULTS: BuildInfo = { config: {}, manifestVersion: 3, release: true, target: 'chrome', version: '1.0.0' }; export default class Environment { - buildTarget: string; - manifestVersion: number; - release: boolean; - version: string; - _buildInfo: BuildInfo; - - // Class reference helpers - can be overridden in children classes - get Class() { - return this.constructor as typeof Environment; - } - // Static constants - static readonly BUILD_INFO = typeof __BUILD__ == 'undefined' ? BUILD_DEFAULTS : __BUILD__; static readonly BROWSER_CHROME = 'chrome'; static readonly BROWSER_EDGE = 'edge'; static readonly BROWSER_FIREFOX = 'firefox'; @@ -77,14 +67,125 @@ export default class Environment { static readonly OS_UNKNOWN = 'unknown'; static readonly OS_WINDOWS = 'windows'; - // Environment values + // Static environment values - computed once and cached + private static readonly _BUILD_INFO = typeof __BUILD__ == 'undefined' ? BUILD_DEFAULTS : __BUILD__; private static readonly _BROWSER_INFO = Environment._computeBrowserInfoSafe(); - static readonly browser = Environment._BROWSER_INFO.browser; - static readonly os = Environment._BROWSER_INFO.os; - static readonly device = Environment._BROWSER_INFO.device; + + // Static getters for browser info + static get browser() { + return this._BROWSER_INFO.browser; + } + static get os() { + return this._BROWSER_INFO.os; + } + static get device() { + return this._BROWSER_INFO.device; + } + + // Static getters for build info + static get buildTarget() { + return this._BUILD_INFO.target; + } + + static get manifestVersion() { + return this._BUILD_INFO.manifestVersion; + } + + static get release() { + return this._BUILD_INFO.release; + } static get version() { - return this.BUILD_INFO.version; + return this._BUILD_INFO.version; + } + + static get 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; } private static _computeBrowserInfoSafe(): BrowserInfo { @@ -185,32 +286,6 @@ export default class Environment { } constructor() { - this._buildInfo = this.Class.BUILD_INFO; - this.buildTarget = this.Class.BUILD_INFO.target; - this.manifestVersion = this.Class.BUILD_INFO.manifestVersion; - this.release = this.Class.BUILD_INFO.release; - this.version = this.Class.BUILD_INFO.version; - } - - // Browser targets - get isChromeTarget(): boolean { - return this.buildTarget === this.Class.BUILD_TARGET_CHROME; - } - - get isFirefoxTarget(): boolean { - return this.buildTarget === this.Class.BUILD_TARGET_FIREFOX; - } - - get isBookmarkletTarget(): boolean { - return this.buildTarget === this.Class.BUILD_TARGET_BOOKMARKLET; - } - - // Builds - get isProduction(): boolean { - return this.release; - } - - get isDevelopment(): boolean { - return !this.isProduction; + throw new Error('Environment is a static class and cannot be instantiated'); } } diff --git a/src/script/WebConfig.ts b/src/script/WebConfig.ts index cd0294e1..e62109f1 100644 --- a/src/script/WebConfig.ts +++ b/src/script/WebConfig.ts @@ -10,7 +10,7 @@ const logger = new Logger('WebConfig'); export default class WebConfig extends Config { _defaultsLoaded: string[]; - _environment: Environment; + _environment: typeof Environment; _lastSplitKeys: { [key: string]: number }; collectStats: boolean; contextMenu: boolean; @@ -335,7 +335,7 @@ export default class WebConfig extends Config { // Apply the Config defaults super(config); - this._environment = new this.Class.Environment(); + this._environment = this.Class.Environment; this.log.setLevel(this.loggingLevel); From 7409e5158bf504d12c39abecb89014d7c4d1b936 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:21 -0600 Subject: [PATCH 05/16] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20(dev)?= =?UTF-8?q?:=20Update=20eslint=20rule=20to=20use=20typeLike=20naming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslint.config.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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'], From d595fe2e21c097722db58d1fe4d8f2b10092ca17 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:27 -0600 Subject: [PATCH 06/16] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20(build):=20UAData?= =?UTF-8?q?=20type=20for=20Environment.=5FcomputeBrowserInfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index 7be6ab2b..e960ec0f 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -30,15 +30,13 @@ interface BuildInfo { version: string; } -interface Navigator { - userAgentData?: UserAgentData; -} - -interface UserAgentData { - brands?: Array<{ brand: string; version: string }>; - mobile?: boolean; - platform?: 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 */ @@ -202,7 +200,7 @@ export default class Environment { private static _computeBrowserInfo(): BrowserInfo { const ua = navigator.userAgent || ''; - const uaData = (navigator as Navigator).userAgentData; + const uaData = (navigator as any).userAgentData as UAData; // iPadOS heuristic (handles Safari reporting MacIntel) const isiPadByPlatform = navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1; From e4b9134bae7544da6329b08821fdb9d12f3bd38b Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:33 -0600 Subject: [PATCH 07/16] =?UTF-8?q?=F0=9F=8E=A8=20(build):=20Handle=20when?= =?UTF-8?q?=20BuildInfo=20isn't=20there=20and=20freeze=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index e960ec0f..51fac390 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -40,7 +40,7 @@ type UAData = // __BUILD__ is injected by webpack from ROOT/.build.json /* eslint-disable-next-line @typescript-eslint/naming-convention */ -declare const __BUILD__: BuildInfo; +declare const __BUILD__: BuildInfo | undefined; const BUILD_DEFAULTS: BuildInfo = { config: {}, manifestVersion: 3, release: true, target: 'chrome', version: '1.0.0' }; export default class Environment { @@ -66,7 +66,9 @@ export default class Environment { static readonly OS_WINDOWS = 'windows'; // Static environment values - computed once and cached - private static readonly _BUILD_INFO = typeof __BUILD__ == 'undefined' ? BUILD_DEFAULTS : __BUILD__; + 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 From 77c6b62348a529328f6dea613a7877ea70977c87 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:39 -0600 Subject: [PATCH 08/16] =?UTF-8?q?=F0=9F=9A=A8=20(dev):=20Fix=20lint=20erro?= =?UTF-8?q?r=20in=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/lib/helper.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/script/lib/helper.ts b/src/script/lib/helper.ts index be504e4b..34ecfc6e 100644 --- a/src/script/lib/helper.ts +++ b/src/script/lib/helper.ts @@ -265,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; From f0f4c5643590f70b54799f1611b871172dcdc043 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:46 -0600 Subject: [PATCH 09/16] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20(build):=20Add=20?= =?UTF-8?q?types=20to=20Environment=20class=20getters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index 51fac390..dd15f128 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -72,34 +72,34 @@ export default class Environment { private static readonly _BROWSER_INFO = Environment._computeBrowserInfoSafe(); // Static getters for browser info - static get browser() { + static get browser(): BrowserInfo['browser'] { return this._BROWSER_INFO.browser; } - static get os() { + static get os(): BrowserInfo['os'] { return this._BROWSER_INFO.os; } - static get device() { + static get device(): BrowserInfo['device'] { return this._BROWSER_INFO.device; } // Static getters for build info - static get buildTarget() { + static get buildTarget(): BuildInfo['target'] { return this._BUILD_INFO.target; } - static get manifestVersion() { + static get manifestVersion(): BuildInfo['manifestVersion'] { return this._BUILD_INFO.manifestVersion; } - static get release() { + static get release(): BuildInfo['release'] { return this._BUILD_INFO.release; } - static get version() { + static get version(): BuildInfo['version'] { return this._BUILD_INFO.version; } - static get config() { + static get config(): BuildInfo['config'] { return this._BUILD_INFO.config; } From dc3ee637a8cdc96a4e61e538e4a76f3c7ac24edc Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:49 -0600 Subject: [PATCH 10/16] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20(dev):=20Mark=20E?= =?UTF-8?q?nvironment=20class=20constants=20as=20const?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index dd15f128..9c252909 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -45,25 +45,25 @@ const BUILD_DEFAULTS: BuildInfo = { config: {}, manifestVersion: 3, release: tru export default class Environment { // Static constants - static readonly BROWSER_CHROME = 'chrome'; - static readonly BROWSER_EDGE = 'edge'; - static readonly BROWSER_FIREFOX = 'firefox'; - static readonly BROWSER_OPERA = 'opera'; - static readonly BROWSER_SAFARI = 'safari'; - static readonly BROWSER_UNKNOWN = 'unknown'; - static readonly BUILD_TARGET_BOOKMARKLET = 'bookmarklet'; - static readonly BUILD_TARGET_CHROME = 'chrome'; - static readonly BUILD_TARGET_FIREFOX = 'firefox'; - static readonly DEVICE_DESKTOP = 'desktop'; - static readonly DEVICE_PHONE = 'phone'; - static readonly DEVICE_TABLET = 'tablet'; - static readonly OS_ANDROID = 'android'; - static readonly OS_CHROMEOS = 'chromeos'; - static readonly OS_IOS = 'ios'; - static readonly OS_LINUX = 'linux'; - static readonly OS_MACOS = 'macos'; - static readonly OS_UNKNOWN = 'unknown'; - static readonly OS_WINDOWS = 'windows'; + 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( From a62310f818d80ac99ea904b684efdfc1bb17195d Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:54 -0600 Subject: [PATCH 11/16] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(dev):=20Allow=20Env?= =?UTF-8?q?ironment=20build=20targets=20to=20be=20extended?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index 9c252909..8811bea1 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -19,14 +19,19 @@ interface BrowserInfo { | 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 & {}); + interface BuildInfo { config: Partial; manifestVersion: number; release: boolean; - target: - | typeof Environment.BUILD_TARGET_BOOKMARKLET - | typeof Environment.BUILD_TARGET_CHROME - | typeof Environment.BUILD_TARGET_FIREFOX; + target: AnyTarget; version: string; } From 04a7c60a437717b3af80b2a38d59cb0296fd8eb6 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:36:59 -0600 Subject: [PATCH 12/16] =?UTF-8?q?=F0=9F=8E=A8=20(config):=20Shorten=20to?= =?UTF-8?q?=20WebConfig.=5Fenv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/OptionPage.ts | 2 +- src/script/Popup.ts | 4 ++-- src/script/WebConfig.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/script/OptionPage.ts b/src/script/OptionPage.ts index 27297b34..d3c54c34 100644 --- a/src/script/OptionPage.ts +++ b/src/script/OptionPage.ts @@ -2187,7 +2187,7 @@ export default class OptionPage { setHelpVersion() { const helpVersion = document.getElementById('helpVersion') as HTMLAnchorElement; - helpVersion.textContent = this.cfg._environment.version; + helpVersion.textContent = this.cfg._env.version; } setupEventListeners() { diff --git a/src/script/Popup.ts b/src/script/Popup.ts index 03bc6bfd..0f0aa2cb 100644 --- a/src/script/Popup.ts +++ b/src/script/Popup.ts @@ -362,8 +362,8 @@ export default class Popup { return ( !this.domain.hostname || this.Class.Page.disabledProtocols.test(this.url.protocol) || - (this.cfg._environment.isChromeTarget && this.Class.Page.disabledChromePages.includes(this.domain.hostname)) || - (this.cfg._environment.isFirefoxTarget && 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 e62109f1..5e8b9414 100644 --- a/src/script/WebConfig.ts +++ b/src/script/WebConfig.ts @@ -10,7 +10,7 @@ const logger = new Logger('WebConfig'); export default class WebConfig extends Config { _defaultsLoaded: string[]; - _environment: typeof Environment; + _env: typeof Environment; _lastSplitKeys: { [key: string]: number }; collectStats: boolean; contextMenu: boolean; @@ -335,7 +335,7 @@ export default class WebConfig extends Config { // Apply the Config defaults super(config); - this._environment = this.Class.Environment; + this._env = this.Class.Environment; this.log.setLevel(this.loggingLevel); @@ -361,7 +361,7 @@ export default class WebConfig extends Config { } localizeDefaults() { - if (this._environment.isBookmarkletTarget || !this._defaultsLoaded || !this._defaultsLoaded.length) return; + if (this._env.isBookmarkletTarget || !this._defaultsLoaded || !this._defaultsLoaded.length) return; const translation = new Translation('common', this.language); From 76b0f8633a8ae592cdbfa3d69ef7eed8f4f2e0d7 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:37:04 -0600 Subject: [PATCH 13/16] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20(dev):=20Export?= =?UTF-8?q?=20type=20interfaces=20from=20classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Background.ts | 4 ++-- src/script/DataMigration.ts | 2 +- src/script/Environment.ts | 4 ++-- src/script/OptionPage.ts | 2 +- src/script/WebFilter.ts | 4 ++-- src/script/lib/Filter.ts | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/script/Background.ts b/src/script/Background.ts index 9a45f8fb..a8816844 100644 --- a/src/script/Background.ts +++ b/src/script/Background.ts @@ -11,7 +11,7 @@ export interface BackgroundData { disabledTab?: boolean; } -interface BackgroundStorage { +export interface BackgroundStorage { tabs?: { [tabId: number]: TabStorageOptions; }; @@ -38,7 +38,7 @@ export interface Message { urlUpdate?: string; } -interface TabStorageOptions { +export interface TabStorageOptions { counters?: { number?: number }; disabled?: boolean; disabledOnce?: number; // NOT_SET: 0, DISABLED: 1, WILL_DISABLE: 2 diff --git a/src/script/DataMigration.ts b/src/script/DataMigration.ts index 0c39be7e..23f762ea 100644 --- a/src/script/DataMigration.ts +++ b/src/script/DataMigration.ts @@ -3,7 +3,7 @@ import { booleanToNumber, getVersion, isVersionOlder } from '@APF/lib/helper'; import WebConfig from '@APF/WebConfig'; import type { WordOptions } from '@APF/lib/Word'; -interface Migration { +export interface Migration { async?: boolean; name: string; runOnImport: boolean; diff --git a/src/script/Environment.ts b/src/script/Environment.ts index 8811bea1..db99ad5f 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -1,6 +1,6 @@ import type WebConfig from '@APF/WebConfig'; -interface BrowserInfo { +export interface BrowserInfo { browser: | typeof Environment.BROWSER_CHROME | typeof Environment.BROWSER_SAFARI @@ -27,7 +27,7 @@ type BaseTarget = // open union: allows extra literal strings later (subclasses) type AnyTarget = BaseTarget | (string & {}); -interface BuildInfo { +export interface BuildInfo { config: Partial; manifestVersion: number; release: boolean; diff --git a/src/script/OptionPage.ts b/src/script/OptionPage.ts index d3c54c34..c9f693f1 100644 --- a/src/script/OptionPage.ts +++ b/src/script/OptionPage.ts @@ -25,7 +25,7 @@ import type { Message } from '@APF/Background'; import type { Statistics } from '@APF/WebFilter'; import type { WordOptions } from '@APF/lib/Word'; -interface ConfirmModalSettings { +export interface ConfirmModalSettings { backup?: boolean; content?: string; title?: string; diff --git a/src/script/WebFilter.ts b/src/script/WebFilter.ts index 66ac0c8d..27f4e6c8 100644 --- a/src/script/WebFilter.ts +++ b/src/script/WebFilter.ts @@ -20,12 +20,12 @@ export interface Summary { }; } -interface WordStatistic { +export interface WordStatistic { text: number; total?: number; } -interface WordStatistics { +export interface WordStatistics { [word: string]: WordStatistic; } diff --git a/src/script/lib/Filter.ts b/src/script/lib/Filter.ts index 258c66d9..c4e1848b 100644 --- a/src/script/lib/Filter.ts +++ b/src/script/lib/Filter.ts @@ -4,7 +4,7 @@ import Wordlist from './Wordlist'; import Config from './Config'; import { randomArrayElement } from './helper'; -interface ReplaceTextResult { +export interface ReplaceTextResult { filtered: string; modified: boolean; original: string; From 44d3d004c61779b18dbbfad9d443025412a741bc Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:37:08 -0600 Subject: [PATCH 14/16] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20(dev):=20Use=20WebCo?= =?UTF-8?q?nfig.Environment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/entry/bookmarklet.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/script/entry/bookmarklet.ts b/src/script/entry/bookmarklet.ts index c790bcd1..444dadaf 100644 --- a/src/script/entry/bookmarklet.ts +++ b/src/script/entry/bookmarklet.ts @@ -1,14 +1,13 @@ /* eslint-disable no-console */ import WebConfig from '@APF/WebConfig'; import BookmarkletFilter from '@APF/BookmarkletFilter'; -import Environment from '@APF/Environment'; /* @preserve - Advanced Profanity Filter by Richard Frost (FrostCo) */ /* @preserve - Start User Config */ const config = WebConfig._defaults as WebConfig; /* @preserve - End User Config */ -console.log(`[APF Bookmarklet] Activated (version ${Environment.version})`); +console.log(`[APF Bookmarklet] Activated (version ${WebConfig.Environment.version})`); if (typeof window !== 'undefined' && !(window).apfBookmarklet) { (window).apfBookmarklet = true; console.log('[APF Bookmarklet] Running'); From a80c9558c555a87ce35e0a1b0f94f969bcfcc080 Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:37:11 -0600 Subject: [PATCH 15/16] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20(dev)?= =?UTF-8?q?:=20Add=20manifest=20version=20helpers=20to=20Environment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/Environment.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/script/Environment.ts b/src/script/Environment.ts index db99ad5f..ceac9968 100644 --- a/src/script/Environment.ts +++ b/src/script/Environment.ts @@ -193,6 +193,15 @@ export default class Environment { 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 { From 4fc212579ba484e081fb0b9f5003f3243318c5bd Mon Sep 17 00:00:00 2001 From: Richard Frost Date: Wed, 20 Aug 2025 20:37:14 -0600 Subject: [PATCH 16/16] =?UTF-8?q?=F0=9F=8E=A8=20(dev):=20Use=20FILTER=5FME?= =?UTF-8?q?THOD.REMOVE=20constant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/script/OptionPage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/OptionPage.ts b/src/script/OptionPage.ts index c9f693f1..79b772e3 100644 --- a/src/script/OptionPage.ts +++ b/src/script/OptionPage.ts @@ -1668,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 }));