From ace783afc3e06e76de3926f8010eb201b5fbefd5 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sat, 17 Oct 2026 05:29:39 +0200 Subject: [PATCH 1/6] Sonar: Removed useless `void` --- src/content/components/base/BaseComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/components/base/BaseComponent.ts b/src/content/components/base/BaseComponent.ts index 30b95b3..7d9afd6 100644 --- a/src/content/components/base/BaseComponent.ts +++ b/src/content/components/base/BaseComponent.ts @@ -77,7 +77,7 @@ export class BaseComponent { ): () => void { this.#container.addEventListener(event, listener, options); - return () => void this.#container.removeEventListener(event, listener, options); + return () => this.#container.removeEventListener(event, listener, options); } /** From 0eafa074f5af0c57ca4b0cc51cf2dffe15b07fba Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sat, 17 Oct 2026 05:30:00 +0200 Subject: [PATCH 2/6] Sonar: Accessing/removing data attributes only through `dataset` --- .../components/extension/profiles/TagsListToggler.ts | 1 - src/content/components/philomena/TagDropdown.ts | 6 ++---- src/content/components/philomena/TagsForm.ts | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/content/components/extension/profiles/TagsListToggler.ts b/src/content/components/extension/profiles/TagsListToggler.ts index c88b564..16a6cef 100644 --- a/src/content/components/extension/profiles/TagsListToggler.ts +++ b/src/content/components/extension/profiles/TagsListToggler.ts @@ -215,7 +215,6 @@ export default class TagsListToggler extends BaseComponent { */ static #markTagElementWithCategory(tagElement: HTMLElement, category: string) { tagElement.dataset.tagCategory = category; - tagElement.setAttribute('data-tag-category', category); } static create(): TagsListToggler { diff --git a/src/content/components/philomena/TagDropdown.ts b/src/content/components/philomena/TagDropdown.ts index 8719281..8786d57 100644 --- a/src/content/components/philomena/TagDropdown.ts +++ b/src/content/components/philomena/TagDropdown.ts @@ -88,14 +88,12 @@ export class TagDropdown extends BaseComponent { // Make sure original category is properly stored. this.originalCategory; - this.container.dataset.tagCategory = targetCategory; - if (targetCategory) { - this.container.setAttribute('data-tag-category', targetCategory); + this.container.dataset.tagCategory = targetCategory; return; } - this.container.removeAttribute('data-tag-category'); + delete this.container.dataset.tagCategory; } /** diff --git a/src/content/components/philomena/TagsForm.ts b/src/content/components/philomena/TagsForm.ts index 8307ed8..58554fd 100644 --- a/src/content/components/philomena/TagsForm.ts +++ b/src/content/components/philomena/TagsForm.ts @@ -127,7 +127,6 @@ export class TagsForm extends BaseComponent { const categoryName = tagCategories.get(tagName)!; tagElement.dataset.tagCategory = categoryName; - tagElement.setAttribute('data-tag-category', categoryName); } } From 304c824045b4f2b1d20fd0e36f1698b8c3af0366 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sat, 17 Oct 2026 05:41:31 +0200 Subject: [PATCH 3/6] Sonar: Explicitly marking some members as `readonly` --- .../components/extension/FullscreenViewer.ts | 36 +++++++++---------- .../extension/ImageShowFullscreenButton.ts | 2 +- .../extension/presets/EditorPresetsBlock.ts | 4 +-- .../extension/presets/PresetTableRow.ts | 4 +-- .../extension/profiles/TaggingProfilePopup.ts | 10 +++--- .../extension/profiles/TagsListToggler.ts | 8 ++--- .../philomena/BlockCommunication.ts | 4 +-- .../components/philomena/TagDropdown.ts | 6 ++-- src/content/components/philomena/TagsForm.ts | 4 +-- .../components/philomena/dupe/DupeDiff.ts | 2 +- .../philomena/dupe/DupeReportRow.ts | 6 ++-- .../philomena/listing/ImageListInfo.ts | 6 ++-- src/lib/extension/BulkEntitiesTransporter.ts | 2 +- src/lib/extension/CustomCategoriesResolver.ts | 8 ++--- .../philomena/scraping/parsing/PostParser.ts | 2 +- 15 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/content/components/extension/FullscreenViewer.ts b/src/content/components/extension/FullscreenViewer.ts index dad4ab5..5c7eb3e 100644 --- a/src/content/components/extension/FullscreenViewer.ts +++ b/src/content/components/extension/FullscreenViewer.ts @@ -11,15 +11,15 @@ import type { TaggingProfilePopup } from "$content/components/extension/profiles export class FullscreenViewer extends BaseComponent { #currentMediaBox: MediaBox | null = null; - #videoElement: HTMLVideoElement = document.createElement('video'); - #imageElement: HTMLImageElement = document.createElement('img'); - #spinnerElement: HTMLElement = document.createElement('i'); - #sizeSelectorElement: HTMLSelectElement = document.createElement('select'); - #closeButtonElement: HTMLElement = document.createElement('i'); - #tagsPopupElement: HTMLElement = document.createElement('div'); - #imageTagsToggler: TagsListToggler = TagsListToggler.create(); - #profileTagsToggler: TagsListToggler = TagsListToggler.create(); - #tagsPopupHider: HTMLElement = document.createElement('div'); + readonly #videoElement: HTMLVideoElement = document.createElement('video'); + readonly #imageElement: HTMLImageElement = document.createElement('img'); + readonly #spinnerElement: HTMLElement = document.createElement('i'); + readonly #sizeSelectorElement: HTMLSelectElement = document.createElement('select'); + readonly #closeButtonElement: HTMLElement = document.createElement('i'); + readonly #tagsPopupElement: HTMLElement = document.createElement('div'); + readonly #imageTagsToggler: TagsListToggler = TagsListToggler.create(); + readonly #profileTagsToggler: TagsListToggler = TagsListToggler.create(); + readonly #tagsPopupHider: HTMLElement = document.createElement('div'); #activeProfileListenerUnsubscriber: UnsubscribeFunction | null = null; #touchId: number | null = null; #startX: number | null = null; @@ -425,21 +425,21 @@ export class FullscreenViewer extends BaseComponent { return url.endsWith('.mp4') || url.endsWith('.webm'); } - static #preferences = new MiscPreferences(); + static readonly #preferences = new MiscPreferences(); - static #offsetProperty = '--offset'; - static #opacityProperty = '--opacity'; - static #shownState = 'shown'; - static #swipeState = 'swiped'; - static #minRequiredDistance = 50; - static #collapsedPopupState = 'is-collapsed'; + static readonly #offsetProperty = '--offset'; + static readonly #opacityProperty = '--opacity'; + static readonly #shownState = 'shown'; + static readonly #swipeState = 'swiped'; + static readonly #minRequiredDistance = 50; + static readonly #collapsedPopupState = 'is-collapsed'; - static #previewSizes: Record = { + static readonly #previewSizes: Record = { full: 'Full', large: 'Large', medium: 'Medium', small: 'Small' } - static #fallbackSize = 'large'; + static readonly #fallbackSize = 'large'; } diff --git a/src/content/components/extension/ImageShowFullscreenButton.ts b/src/content/components/extension/ImageShowFullscreenButton.ts index 6d21c91..e61ff55 100644 --- a/src/content/components/extension/ImageShowFullscreenButton.ts +++ b/src/content/components/extension/ImageShowFullscreenButton.ts @@ -81,5 +81,5 @@ export class ImageShowFullscreenButton extends BaseComponent { return viewer; } - static #preferences = new MiscPreferences(); + static readonly #preferences = new MiscPreferences(); } diff --git a/src/content/components/extension/presets/EditorPresetsBlock.ts b/src/content/components/extension/presets/EditorPresetsBlock.ts index 80cba5c..27a62b6 100644 --- a/src/content/components/extension/presets/EditorPresetsBlock.ts +++ b/src/content/components/extension/presets/EditorPresetsBlock.ts @@ -5,8 +5,8 @@ import { createFontAwesomeIcon } from "$lib/dom-utils"; import { sortEntitiesByField } from "$lib/utils"; export default class EditorPresetsBlock extends BaseComponent { - #presetsTable = document.createElement('table'); - #presetBlocks: PresetTableRow[] = []; + readonly #presetsTable = document.createElement('table'); + readonly #presetBlocks: PresetTableRow[] = []; #tags: Set = new Set(); protected build() { diff --git a/src/content/components/extension/presets/PresetTableRow.ts b/src/content/components/extension/presets/PresetTableRow.ts index a38fa9e..8c7667f 100644 --- a/src/content/components/extension/presets/PresetTableRow.ts +++ b/src/content/components/extension/presets/PresetTableRow.ts @@ -207,6 +207,6 @@ export default class PresetTableRow extends BaseComponent { return new this(document.createElement('tr'), preset); } - static #tagMissingClassName = 'is-missing'; - static #presetWarningClassName = 'has-warning'; + static readonly #tagMissingClassName = 'is-missing'; + static readonly #presetWarningClassName = 'has-warning'; } diff --git a/src/content/components/extension/profiles/TaggingProfilePopup.ts b/src/content/components/extension/profiles/TaggingProfilePopup.ts index 2274101..272acca 100644 --- a/src/content/components/extension/profiles/TaggingProfilePopup.ts +++ b/src/content/components/extension/profiles/TaggingProfilePopup.ts @@ -16,14 +16,14 @@ import { EVENT_TAG_TOGGLED } from "$content/components/events/tags-list-toggler- export class TaggingProfilePopup extends BaseComponent { - #tagsListToggler = TagsListToggler.create(); + readonly #tagsListToggler = TagsListToggler.create(); #activeProfile: TaggingProfile | null = null; #mediaBoxTools: MediaBoxTools | null = null; #isSubmissionLocked: boolean = false; #isPlanningToSubmit: boolean = false; #isSubmitting: boolean = false; #tagsSubmissionTimer: Timeout | null = null; - #emitter = emitterAt(this); + readonly #emitter = emitterAt(this); /** * @protected @@ -226,7 +226,7 @@ export class TaggingProfilePopup extends BaseComponent { /** * Controller with maintenance settings. */ - static #preferences = new TaggingProfilesPreferences(); + static readonly #preferences = new TaggingProfilesPreferences(); /** * Subscribe to all necessary feeds to watch for every active profile change. Additionally, will execute the callback @@ -298,9 +298,9 @@ export class TaggingProfilePopup extends BaseComponent { }); } - static #scrapedAPI = new ScrapedAPI(); + static readonly #scrapedAPI = new ScrapedAPI(); - static #delayBeforeSubmissionMs = 500; + static readonly #delayBeforeSubmissionMs = 500; /** * Amount of pending submissions or NULL if logic was not yet initialized. diff --git a/src/content/components/extension/profiles/TagsListToggler.ts b/src/content/components/extension/profiles/TagsListToggler.ts index 16a6cef..ecc70e8 100644 --- a/src/content/components/extension/profiles/TagsListToggler.ts +++ b/src/content/components/extension/profiles/TagsListToggler.ts @@ -222,11 +222,11 @@ export default class TagsListToggler extends BaseComponent { return new TagsListToggler(tagsListContainer); } - static #containsClass = 'is-present'; - static #missingClass = 'is-missing'; + static readonly #containsClass = 'is-present'; + static readonly #missingClass = 'is-missing'; - static #addedClass = 'is-added'; - static #removedClass = 'is-removed'; + static readonly #addedClass = 'is-added'; + static readonly #removedClass = 'is-removed'; } export class BlackListedTagsEncounteredError extends Error { diff --git a/src/content/components/philomena/BlockCommunication.ts b/src/content/components/philomena/BlockCommunication.ts index da192e3..0da2c1f 100644 --- a/src/content/components/philomena/BlockCommunication.ts +++ b/src/content/components/philomena/BlockCommunication.ts @@ -112,14 +112,14 @@ export class BlockCommunication extends BaseComponent { ); } - static #preferences = new TagsPreferences(); + static readonly #preferences = new TagsPreferences(); /** * Map of links to their original texts. These texts need to be stored here to make them restorable. Keys is a link * element and value is a text. * @private */ - static #originalTagLinkTexts: WeakMap = new WeakMap(); + static readonly #originalTagLinkTexts: WeakMap = new WeakMap(); static findAndInitializeAll() { for (const container of document.querySelectorAll('.block.communication')) { diff --git a/src/content/components/philomena/TagDropdown.ts b/src/content/components/philomena/TagDropdown.ts index 8786d57..21f6b1b 100644 --- a/src/content/components/philomena/TagDropdown.ts +++ b/src/content/components/philomena/TagDropdown.ts @@ -201,7 +201,7 @@ export class TagDropdown extends BaseComponent { await this.#activeProfile.save(); } - static #preferences = new TaggingProfilesPreferences(); + static readonly #preferences = new TaggingProfilesPreferences(); /** * Watch for changes to active profile. @@ -260,8 +260,8 @@ export class TagDropdown extends BaseComponent { return dropdownLink; } - static #categoriesResolver = new CustomCategoriesResolver(); - static #processedElements: WeakSet = new WeakSet(); + static readonly #categoriesResolver = new CustomCategoriesResolver(); + static readonly #processedElements: WeakSet = new WeakSet(); static #findAll(parentNode: ParentNode = document): NodeListOf { return parentNode.querySelectorAll('.tag.dropdown'); diff --git a/src/content/components/philomena/TagsForm.ts b/src/content/components/philomena/TagsForm.ts index 58554fd..76ce50e 100644 --- a/src/content/components/philomena/TagsForm.ts +++ b/src/content/components/philomena/TagsForm.ts @@ -7,8 +7,8 @@ import EditorPresetsBlock from "$content/components/extension/presets/EditorPres import { EVENT_PRESET_TAG_CHANGE_APPLIED, type PresetTagChange } from "$content/components/events/preset-block-events"; export class TagsForm extends BaseComponent { - #togglePresetsButton: HTMLButtonElement = document.createElement('button'); - #presetsList = EditorPresetsBlock.create(); + readonly #togglePresetsButton: HTMLButtonElement = document.createElement('button'); + readonly #presetsList = EditorPresetsBlock.create(); #plainEditorTextarea: HTMLTextAreaElement | null = null; #fancyEditorInput: HTMLInputElement | null = null; #tagsSet: Set = new Set(); diff --git a/src/content/components/philomena/dupe/DupeDiff.ts b/src/content/components/philomena/dupe/DupeDiff.ts index c4f73d9..50f7666 100644 --- a/src/content/components/philomena/dupe/DupeDiff.ts +++ b/src/content/components/philomena/dupe/DupeDiff.ts @@ -104,7 +104,7 @@ export default class DupeDiff extends BaseComponent { * * Keys are the icons and values are the patterns extension should check for each URL. */ - static #iconsToPatternsMap = new Map([ + static readonly #iconsToPatternsMap = new Map([ [ ['artstation', brandsSubtype], 'artstation.com' diff --git a/src/content/components/philomena/dupe/DupeReportRow.ts b/src/content/components/philomena/dupe/DupeReportRow.ts index 5b9ab9f..b927f35 100644 --- a/src/content/components/philomena/dupe/DupeReportRow.ts +++ b/src/content/components/philomena/dupe/DupeReportRow.ts @@ -4,9 +4,9 @@ import DupeImage from "$content/components/philomena/dupe/DupeImage"; import { ratingTags } from "$config/tags"; export default class DupeReportRow extends BaseComponent { - #leftImage: DupeImage; - #rightImage: DupeImage; - #difference: DupeDiff; + readonly #leftImage: DupeImage; + readonly #rightImage: DupeImage; + readonly #difference: DupeDiff; constructor(leftCell: HTMLElement, rightCell: HTMLElement, diffCell: HTMLElement, reportOptions: HTMLElement) { super(reportOptions); diff --git a/src/content/components/philomena/listing/ImageListInfo.ts b/src/content/components/philomena/listing/ImageListInfo.ts index 44fbd21..fb62afa 100644 --- a/src/content/components/philomena/listing/ImageListInfo.ts +++ b/src/content/components/philomena/listing/ImageListInfo.ts @@ -2,8 +2,8 @@ import { BaseComponent } from "$content/components/base/BaseComponent"; export class ImageListInfo extends BaseComponent { #tagElement: HTMLElement | null = null; - #impliedTags: string[] = []; - #showUntaggedImplicationsButton: HTMLAnchorElement = document.createElement('a'); + readonly #impliedTags: string[] = []; + readonly #showUntaggedImplicationsButton: HTMLAnchorElement = document.createElement('a'); protected build() { const sectionAfterImage = this.container.querySelector('.tag-info__image + .flex__grow'); @@ -71,5 +71,5 @@ export class ImageListInfo extends BaseComponent { location.assign(url.href); } - static #implicationsStarterText = 'Implies:'; + static readonly #implicationsStarterText = 'Implies:'; } diff --git a/src/lib/extension/BulkEntitiesTransporter.ts b/src/lib/extension/BulkEntitiesTransporter.ts index 08ed77c..68645e4 100644 --- a/src/lib/extension/BulkEntitiesTransporter.ts +++ b/src/lib/extension/BulkEntitiesTransporter.ts @@ -101,7 +101,7 @@ export default class BulkEntitiesTransporter { && Array.isArray(targetObject.elements); } - static #transporters: TransportersMapping = { + static readonly #transporters: TransportersMapping = { profiles: new EntitiesTransporter(TaggingProfile), groups: new EntitiesTransporter(TagGroup), presets: new EntitiesTransporter(TagEditorPreset), diff --git a/src/lib/extension/CustomCategoriesResolver.ts b/src/lib/extension/CustomCategoriesResolver.ts index 74d67b7..e658d87 100644 --- a/src/lib/extension/CustomCategoriesResolver.ts +++ b/src/lib/extension/CustomCategoriesResolver.ts @@ -5,9 +5,9 @@ import { emit } from "$content/components/events/comms"; import { EVENT_TAG_GROUP_RESOLVED } from "$content/components/events/tag-dropdown-events"; export default class CustomCategoriesResolver { - #exactGroupMatches = new Map(); - #regExpGroupMatches = new Map(); - #tagDropdowns: TagDropdown[] = []; + readonly #exactGroupMatches = new Map(); + readonly #regExpGroupMatches = new Map(); + readonly #tagDropdowns: TagDropdown[] = []; #nextQueuedUpdate: Timeout | null = null; constructor() { @@ -125,5 +125,5 @@ export default class CustomCategoriesResolver { ); } - static #unprocessedTagsTimeout = 0; + static readonly #unprocessedTagsTimeout = 0; } diff --git a/src/lib/philomena/scraping/parsing/PostParser.ts b/src/lib/philomena/scraping/parsing/PostParser.ts index e7c6822..1963db7 100644 --- a/src/lib/philomena/scraping/parsing/PostParser.ts +++ b/src/lib/philomena/scraping/parsing/PostParser.ts @@ -78,5 +78,5 @@ export default class PostParser extends PageParser { ); } - static tagsInputName = 'image[tag_input]'; + static readonly tagsInputName = 'image[tag_input]'; } From 05349feafcee90c71466827bfae9159c0e145e9f Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sat, 17 Oct 2026 05:41:53 +0200 Subject: [PATCH 4/6] Sonar: Check for `undefined` without `typeof` --- src/content/components/extension/FullscreenViewer.ts | 2 +- src/content/deps/amd.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/components/extension/FullscreenViewer.ts b/src/content/components/extension/FullscreenViewer.ts index 5c7eb3e..4169e3f 100644 --- a/src/content/components/extension/FullscreenViewer.ts +++ b/src/content/components/extension/FullscreenViewer.ts @@ -412,7 +412,7 @@ export class FullscreenViewer extends BaseComponent { } #togglePopupVisibility(maybeState: boolean | undefined = undefined) { - if (typeof maybeState === 'undefined') { + if (maybeState === undefined) { const isHidden = this.#tagsPopupElement.classList.toggle(FullscreenViewer.#collapsedPopupState); void FullscreenViewer.#preferences.fullscreenViewerPopupShown.set(!isHidden); return; diff --git a/src/content/deps/amd.ts b/src/content/deps/amd.ts index 1ced3ee..f3e7824 100644 --- a/src/content/deps/amd.ts +++ b/src/content/deps/amd.ts @@ -38,7 +38,7 @@ amdLite.define = (name, dependencies, originalCallback) => { // Workaround for the entry script not returning anything causing AMD-Lite to send warning about modules not // being loaded/not existing. - return typeof callbackResult !== 'undefined' ? callbackResult : {}; + return callbackResult !== undefined ? callbackResult : {}; }); // Schedule the auto run on the next available frame. Firefox and Chromium have a lot of differences in how they From 971f9b8a60f6167f9912c37dfae6571f9bd160c6 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sat, 17 Oct 2026 05:42:00 +0200 Subject: [PATCH 5/6] Removed unused import --- src/lib/extension/EntitiesTransporter.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/extension/EntitiesTransporter.ts b/src/lib/extension/EntitiesTransporter.ts index 0b90cec..c8dc604 100644 --- a/src/lib/extension/EntitiesTransporter.ts +++ b/src/lib/extension/EntitiesTransporter.ts @@ -2,7 +2,6 @@ import { validateImportedEntity } from "$lib/extension/transporting/validators"; import { exportEntityToObject } from "$lib/extension/transporting/exporters"; import StorageEntity from "$lib/extension/base/StorageEntity"; import { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from "lz-string"; -import type { ImportableElement } from "$lib/extension/transporting/importables"; /** * Status of the last import. From 37a8e77f97c285aa1a6d95ed84ac04b03fbc99b5 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sat, 17 Oct 2026 05:43:56 +0200 Subject: [PATCH 6/6] Sonar: Replacing regular `for` with `for..of` --- src/content/components/extension/profiles/TagsListToggler.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/content/components/extension/profiles/TagsListToggler.ts b/src/content/components/extension/profiles/TagsListToggler.ts index ecc70e8..9efeba2 100644 --- a/src/content/components/extension/profiles/TagsListToggler.ts +++ b/src/content/components/extension/profiles/TagsListToggler.ts @@ -64,9 +64,7 @@ export default class TagsListToggler extends BaseComponent { const hasStoredChanges = this.hasChanges; - for (let tagIndex = 0; tagIndex < toggleableTags.length; tagIndex++) { - const tagName = toggleableTags[tagIndex]; - + for (const tagName of toggleableTags) { if (this.#renderedTags.has(tagName)) { continue; } @@ -74,7 +72,6 @@ export default class TagsListToggler extends BaseComponent { this.#renderedTags.add(tagName); const tagElement = TagsListToggler.#buildTagElement(tagName); - this.#tagsList.push(tagElement); const isPresent = activeTags.has(tagName);