diff --git a/source/content-scripts/features/autocomplete.tsx b/source/content-scripts/features/autocomplete.tsx index 2ec60d0..43ef76a 100644 --- a/source/content-scripts/features/autocomplete.tsx +++ b/source/content-scripts/features/autocomplete.tsx @@ -1,6 +1,6 @@ import {offset, type Offset} from "caret-pos"; import {Component} from "preact"; -import {type UserLabelsData} from "../../storage/common.js"; +import {type UserLabelsData} from "../../storage/exports.js"; import {log, querySelectorAll} from "../../utilities/exports.js"; type Props = { diff --git a/source/content-scripts/features/hide-votes.ts b/source/content-scripts/features/hide-votes.ts index f261741..e96d380 100644 --- a/source/content-scripts/features/hide-votes.ts +++ b/source/content-scripts/features/hide-votes.ts @@ -1,4 +1,4 @@ -import {type HideVotesData} from "../../storage/common.js"; +import {type HideVotesData} from "../../storage/exports.js"; import {log, querySelectorAll} from "../../utilities/exports.js"; export function runHideVotesFeature(data: HideVotesData) { diff --git a/source/content-scripts/features/user-labels.tsx b/source/content-scripts/features/user-labels.tsx index 7ec5f8f..ee52935 100644 --- a/source/content-scripts/features/user-labels.tsx +++ b/source/content-scripts/features/user-labels.tsx @@ -4,7 +4,7 @@ import { type UserLabelsData, createValueUserLabel, saveUserLabels, -} from "../../storage/common.js"; +} from "../../storage/exports.js"; import { createElementFromString, isColorBright, diff --git a/source/content-scripts/features/username-colors.ts b/source/content-scripts/features/username-colors.ts index bf38db8..7bcfee1 100644 --- a/source/content-scripts/features/username-colors.ts +++ b/source/content-scripts/features/username-colors.ts @@ -1,5 +1,5 @@ import {log, querySelectorAll} from "../../utilities/exports.js"; -import {type UsernameColorsData} from "../../storage/common.js"; +import {type UsernameColorsData} from "../../storage/exports.js"; export function runUsernameColorsFeature( data: UsernameColorsData, diff --git a/source/content-scripts/setup.tsx b/source/content-scripts/setup.tsx index 1dfcb01..20f1482 100644 --- a/source/content-scripts/setup.tsx +++ b/source/content-scripts/setup.tsx @@ -1,6 +1,6 @@ import {type JSX, render} from "preact"; import {extractGroups, initializeGlobals, log} from "../utilities/exports.js"; -import {Feature, fromStorage, Data} from "../storage/common.js"; +import {Feature, fromStorage, Data} from "../storage/exports.js"; import { AutocompleteFeature, BackToTopFeature, diff --git a/source/options/components/hide-votes.tsx b/source/options/components/hide-votes.tsx index 48bb847..103a56d 100644 --- a/source/options/components/hide-votes.tsx +++ b/source/options/components/hide-votes.tsx @@ -4,7 +4,7 @@ import { fromStorage, Feature, type HideVotesData, -} from "../../storage/common.js"; +} from "../../storage/exports.js"; import {Setting, type SettingProps} from "./index.js"; type State = { diff --git a/source/options/components/index.tsx b/source/options/components/index.tsx index ff575eb..4b66ac2 100644 --- a/source/options/components/index.tsx +++ b/source/options/components/index.tsx @@ -2,7 +2,7 @@ import {Component, type ComponentChildren, type JSX} from "preact"; // eslint-disable-next-line n/file-extension-in-import import {useContext} from "preact/hooks"; import {AppContext} from "../context.js"; -import {type Feature} from "../../storage/common.js"; +import {type Feature} from "../../storage/exports.js"; export type SettingProps = { children: ComponentChildren; diff --git a/source/options/components/username-colors.tsx b/source/options/components/username-colors.tsx index ee956f6..9d13b7f 100644 --- a/source/options/components/username-colors.tsx +++ b/source/options/components/username-colors.tsx @@ -6,7 +6,7 @@ import { type UsernameColor, Feature, fromStorage, -} from "../../storage/common.js"; +} from "../../storage/exports.js"; import {Setting, type SettingProps} from "./index.js"; type State = { diff --git a/source/options/context.ts b/source/options/context.ts index 85ae439..d764d6f 100644 --- a/source/options/context.ts +++ b/source/options/context.ts @@ -1,5 +1,5 @@ import {createContext} from "preact"; -import {type Feature} from "../storage/common.js"; +import {type Feature} from "../storage/exports.js"; type AppContextValues = { setActiveFeature: (feature: Feature) => void; diff --git a/source/options/features.ts b/source/options/features.ts index ee8fc50..c672d0c 100644 --- a/source/options/features.ts +++ b/source/options/features.ts @@ -1,4 +1,4 @@ -import {Feature} from "../storage/common.js"; +import {Feature} from "../storage/exports.js"; import { AboutSetting, AnonymizeUsernamesSetting, diff --git a/source/options/setup.tsx b/source/options/setup.tsx index 86582a5..c27b5de 100644 --- a/source/options/setup.tsx +++ b/source/options/setup.tsx @@ -7,7 +7,7 @@ import { createReportTemplate, initializeGlobals, } from "../utilities/exports.js"; -import {type Feature, Data, fromStorage} from "../storage/common.js"; +import {type Feature, Data, fromStorage} from "../storage/exports.js"; import {AppContext} from "./context.js"; import {features} from "./features.js"; diff --git a/source/options/user-label-editor.tsx b/source/options/user-label-editor.tsx index c4f725f..5c6cbc4 100644 --- a/source/options/user-label-editor.tsx +++ b/source/options/user-label-editor.tsx @@ -12,7 +12,7 @@ import { Feature, createValueUserLabel, saveUserLabels, -} from "../storage/common.js"; +} from "../storage/exports.js"; import "../scss/index.scss"; import "../scss/user-label-editor.scss"; diff --git a/source/storage/enums.ts b/source/storage/enums.ts new file mode 100644 index 0000000..c40eece --- /dev/null +++ b/source/storage/enums.ts @@ -0,0 +1,19 @@ +export enum Feature { + AnonymizeUsernames = "anonymize-usernames", + Autocomplete = "autocomplete", + BackToTop = "back-to-top", + Debug = "debug", + HideVotes = "hide-votes", + JumpToNewComment = "jump-to-new-comment", + MarkdownToolbar = "markdown-toolbar", + ThemedLogo = "themed-logo", + UserLabels = "user-labels", + UsernameColors = "username-colors", +} + +export enum Data { + EnabledFeatures = "enabled-features", + KnownGroups = "known-groups", + LatestActiveFeatureTab = "latest-active-feature-tab", + Version = "data-version", +} diff --git a/source/storage/common.ts b/source/storage/exports.ts similarity index 50% rename from source/storage/common.ts rename to source/storage/exports.ts index 54ea869..9578325 100644 --- a/source/storage/common.ts +++ b/source/storage/exports.ts @@ -1,25 +1,10 @@ import {createValue, type Value} from "@holllo/webextension-storage"; import browser from "webextension-polyfill"; +import {collectUserLabels} from "./user-label.js"; +import {Data, Feature} from "./enums.js"; -export enum Feature { - AnonymizeUsernames = "anonymize-usernames", - Autocomplete = "autocomplete", - BackToTop = "back-to-top", - Debug = "debug", - HideVotes = "hide-votes", - JumpToNewComment = "jump-to-new-comment", - MarkdownToolbar = "markdown-toolbar", - ThemedLogo = "themed-logo", - UserLabels = "user-labels", - UsernameColors = "username-colors", -} - -export enum Data { - EnabledFeatures = "enabled-features", - KnownGroups = "known-groups", - LatestActiveFeatureTab = "latest-active-feature-tab", - Version = "data-version", -} +export * from "./user-label.js"; +export * from "./enums.js"; export type HideVotesData = { otherComments: boolean; @@ -28,16 +13,6 @@ export type HideVotesData = { ownTopics: boolean; }; -export type UserLabel = { - color: string; - id: number; - priority: number; - text: string; - username: string; -}; - -export type UserLabelsData = Array>; - export type UsernameColor = { color: string; id: number; @@ -46,56 +21,6 @@ export type UsernameColor = { export type UsernameColorsData = UsernameColor[]; -/** - * Create a {@link Value}-wrapped {@link UserLabel}. - */ -export async function createValueUserLabel( - userLabel: UserLabel, -): Promise { - return createValue({ - deserialize: (input) => JSON.parse(input) as UserLabel, - serialize: (input) => JSON.stringify(input), - key: `${Feature.UserLabels}-${userLabel.id}`, - value: userLabel, - storage: browser.storage.sync, - }); -} - -/** - * Get all user labels from storage and combine them into a single array. - */ -export async function collectUserLabels(): Promise { - const storage = await browser.storage.sync.get(); - const userLabels = []; - for (const [key, value] of Object.entries(storage)) { - if (!key.startsWith(Feature.UserLabels)) { - continue; - } - - userLabels.push( - await createValueUserLabel(JSON.parse(value as string) as UserLabel), - ); - } - - return userLabels; -} - -/** - * Save all user labels to storage under individual keys. - * - * They are stored under individual keys so that we don't run into storage quota - * limits. If it was stored under a single key we would only be able to fit - * around 80-100 labels before hitting the limit. - * @param userLabels The user labels array to save. - */ -export async function saveUserLabels( - userLabels: UserLabelsData, -): Promise { - for (const label of userLabels) { - await label.save(); - } -} - export const storageValues = { [Data.EnabledFeatures]: createValue({ deserialize: (input) => new Set(JSON.parse(input) as Feature[]), @@ -137,7 +62,6 @@ export const storageValues = { }, storage: browser.storage.sync, }), - // eslint-disable-next-line unicorn/prefer-top-level-await [Feature.UserLabels]: collectUserLabels(), [Feature.UsernameColors]: createValue({ deserialize: (input) => JSON.parse(input) as UsernameColorsData, diff --git a/source/storage/migrations/migrations.test.ts b/source/storage/migrations/migrations.test.ts index 27e7fbe..e2a5e02 100644 --- a/source/storage/migrations/migrations.test.ts +++ b/source/storage/migrations/migrations.test.ts @@ -1,6 +1,6 @@ import browser from "webextension-polyfill"; import {setup} from "@holllo/test"; -import {Data, Feature} from "../common.js"; +import {Data, Feature} from "../exports.js"; import {migrations} from "./migrations.js"; import {v112Sample} from "./v1-1-2.js"; diff --git a/source/storage/migrations/migrations.ts b/source/storage/migrations/migrations.ts index f8a1205..6c20065 100644 --- a/source/storage/migrations/migrations.ts +++ b/source/storage/migrations/migrations.ts @@ -1,13 +1,11 @@ -import {setup} from "@holllo/test"; import {type Migration} from "@holllo/migration-helper"; -import browser from "webextension-polyfill"; import { Data, Feature, createValueUserLabel, fromStorage, saveUserLabels, -} from "../common.js"; +} from "../exports.js"; import {v112DeserializeData, v112Sample, type V112Settings} from "./v1-1-2.js"; export const migrations: Array> = [ diff --git a/source/storage/user-label.ts b/source/storage/user-label.ts new file mode 100644 index 0000000..008db4d --- /dev/null +++ b/source/storage/user-label.ts @@ -0,0 +1,63 @@ +import {createValue, type Value} from "@holllo/webextension-storage"; +import browser from "webextension-polyfill"; +import {Feature} from "./enums.js"; + +export type UserLabel = { + color: string; + id: number; + priority: number; + text: string; + username: string; +}; + +export type UserLabelsData = Array>; + +/** + * Create a {@link Value}-wrapped {@link UserLabel}. + */ +export async function createValueUserLabel( + userLabel: UserLabel, +): Promise { + return createValue({ + deserialize: (input) => JSON.parse(input) as UserLabel, + serialize: (input) => JSON.stringify(input), + key: `${Feature.UserLabels}-${userLabel.id}`, + value: userLabel, + storage: browser.storage.sync, + }); +} + +/** + * Get all user labels from storage and combine them into a single array. + */ +export async function collectUserLabels(): Promise { + const storage = await browser.storage.sync.get(); + const userLabels = []; + for (const [key, value] of Object.entries(storage)) { + if (!key.startsWith(Feature.UserLabels)) { + continue; + } + + userLabels.push( + await createValueUserLabel(JSON.parse(value as string) as UserLabel), + ); + } + + return userLabels; +} + +/** + * Save all user labels to storage under individual keys. + * + * They are stored under individual keys so that we don't run into storage quota + * limits. If it was stored under a single key we would only be able to fit + * around 80-100 labels before hitting the limit. + * @param userLabels The user labels array to save. + */ +export async function saveUserLabels( + userLabels: UserLabelsData, +): Promise { + for (const label of userLabels) { + await label.save(); + } +}