Skip to content

Commit

Permalink
use more readonly
Browse files Browse the repository at this point in the history
  • Loading branch information
GooseOb committed Nov 30, 2024
1 parent 68c39eb commit a469cde
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 22 deletions.
51 changes: 29 additions & 22 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ declare const STORAGE_NAME: 'YTDefaulter',
QUALITY: 'quality',
VOLUME: 'volume';

const override = Object.assign as <T>(a: T, b: Partial<T>) => T;

const translations: Record<string, Partial<typeof text>> = {
'be-BY': {
OPEN_SETTINGS: 'Адкрыць дадатковыя налады',
Expand Down Expand Up @@ -56,7 +54,7 @@ const text = {
EXPORT: 'Export',
IMPORT: 'Import',
};
override(text, translations[document.documentElement.lang]);
Object.assign(text, translations[document.documentElement.lang]);

const cfgLocalStorage = localStorage[STORAGE_NAME];
let cfg: ScriptCfg = cfgLocalStorage
Expand All @@ -74,16 +72,17 @@ let cfg: ScriptCfg = cfgLocalStorage
},
};
const isDescendantOrTheSame = (
child: Element | ParentNode,
parents: ParentNode[]
child: Readonly<Element | ParentNode>,
parents: readonly Readonly<ParentNode>[]
): boolean => {
while (child !== null) {
if (parents.includes(child)) return true;
child = child.parentNode;
}
return false;
};
const saveCfg = (cfg: ScriptCfg) => {

const saveCfg = (cfg: DeepReadonly<ScriptCfg>) => {
const cfgCopy = { ...cfg };
const channelsCfgCopy = { ...cfg.channels };
outer: for (const key in channelsCfgCopy) {
Expand All @@ -97,7 +96,7 @@ const saveCfg = (cfg: ScriptCfg) => {
localStorage[STORAGE_NAME] = JSON.stringify(cfgCopy);
};

const updateValuesIn = (controls: SettingControls, cfgPart: Cfg) => {
const updateValuesIn = (controls: SettingControls, cfgPart: Readonly<Cfg>) => {
controls[SPEED].value = cfgPart[SPEED] || text.DEFAULT;
controls[CUSTOM_SPEED].value = cfgPart[CUSTOM_SPEED] || '';
controls[QUALITY].value = cfgPart[QUALITY] || text.DEFAULT;
Expand Down Expand Up @@ -282,14 +281,14 @@ const isMusicChannel = (aboveTheFold: HTMLElement) =>
!!aboveTheFold.querySelector('.badge-style-type-verified-artist');

const findInNodeList = <T extends HTMLElement>(
list: NodeListOf<T>,
list: DeepReadonly<NodeListOf<T>>,
finder: (item: T) => boolean
) => {
for (const item of list) if (finder(item)) return item;
};

const ytMenu = {
async setPlayer(plr: HTMLElement) {
async setPlayer(plr: Readonly<HTMLElement>) {
this.element = plr.querySelector('.ytp-settings-menu');
this._btn = plr.querySelector('.ytp-settings-button');
const clickBtn = this._btn.click.bind(this._btn);
Expand All @@ -305,7 +304,7 @@ const ytMenu = {
setOpen(bool: boolean) {
if (bool !== this.isOpen()) this._btn.click();
},
openItem(item: YtSettingItem) {
openItem(item: Readonly<YtSettingItem>) {
this.setOpen(true);
item.click();
return this.element.querySelectorAll(
Expand All @@ -316,7 +315,7 @@ const ytMenu = {
[SPEED]: null,
[QUALITY]: null,
} as Record<YtSettingName, YtSettingItem | null>,
setSettingItems(items: NodeListOf<YtSettingItem>) {
setSettingItems(items: DeepReadonly<NodeListOf<YtSettingItem>>) {
const findIcon = (d: string) =>
findInNodeList(items, (el) => !!el.querySelector(`path[d="${d}"]`));

Expand All @@ -327,7 +326,10 @@ const ytMenu = {
'M15,17h6v1h-6V17z M11,17H3v1h8v2h1v-2v-1v-2h-1V17z M14,8h1V6V5V3h-1v2H3v1h11V8z M18,5v1h3V5H18z M6,14h1v-2v-1V9H6v2H3v1 h3V14z M10,12h11v-1H10V12z'
);
},
findInItem(name: YtSettingName, finder: (item: HTMLElement) => boolean) {
findInItem(
name: YtSettingName,
finder: (item: Readonly<HTMLElement>) => boolean
) {
return findInNodeList(this.openItem(this.settingItems[name]), finder);
},
};
Expand All @@ -346,10 +348,12 @@ const validateVolume = (value: string) => {
type Props<T extends HTMLElement> = Partial<T> & object;
const getElCreator =
<TTag extends keyof HTMLElementTagNameMap>(tag: TTag) =>
<TProps extends Props<HTMLElementTagNameMap[TTag]>>(props?: TProps) =>
override(document.createElement(tag), props);
<TProps extends Props<HTMLElementTagNameMap[TTag]>>(
props?: DeepReadonly<TProps>
) =>
Object.assign(document.createElement(tag), props);
type Comparator = (target: string, current: string) => boolean;
const comparators: Record<YtSettingName, Comparator> = {
const comparators: { readonly [P in YtSettingName]: Comparator } = {
// assuming the search is from the top
[QUALITY]: (target, current) =>
+target >= parseInt(current) &&
Expand All @@ -360,7 +364,7 @@ const logger = {
// log(...msgs: string[]) {
// console.log('[YT-Defaulter]', ...msgs);
// },
err(...msgs: string[]) {
err(...msgs: readonly string[]) {
console.error('[YT-Defaulter]', ...msgs);
},
outOfRange(what: string) {
Expand Down Expand Up @@ -418,11 +422,14 @@ const valueSetters: ValueSetters & ValueSetterHelpers = {
};
const div = getElCreator('div'),
input = getElCreator('input'),
checkbox = <T extends Props<HTMLInputElement>>(props?: T) =>
checkbox = <T extends Props<HTMLInputElement>>(props?: DeepReadonly<T>) =>
input({ type: 'checkbox', ...props }),
option = getElCreator('option'),
_label = getElCreator('label'),
labelEl = <T extends Props<HTMLLabelElement>>(forId: string, props?: T) => {
labelEl = <T extends Props<HTMLLabelElement>>(
forId: string,
props?: DeepReadonly<T>
) => {
const elem = _label(props);
elem.setAttribute('for', forId);
return elem;
Expand All @@ -433,7 +440,7 @@ const div = getElCreator('div'),
_button = getElCreator('button'),
button = <T extends Props<HTMLButtonElement>>(
textContent: string,
props?: T
props?: DeepReadonly<T>
) =>
_button({
textContent,
Expand All @@ -447,8 +454,8 @@ const div = getElCreator('div'),
...props,
});

class Hint<TProps extends Props<HTMLDivElement> = any> {
constructor(prefix: string, props?: TProps) {
class Hint {
constructor(prefix: string, props?: DeepReadonly<Props<HTMLDivElement>>) {
this.element = div(props);
this.element.className ||= SETTING_HINT_CLASS;
this.prefix = prefix;
Expand All @@ -462,7 +469,7 @@ class Hint<TProps extends Props<HTMLDivElement> = any> {
if (msg) this.element.textContent = this.prefix + msg;
}
private prefix: string;
element: HTMLElement;
element: HTMLDivElement;
}

const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
Expand Down
12 changes: 12 additions & 0 deletions types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
type DeepReadonly<T> = T extends (infer R)[]
? DeepReadonlyArray<R>
: T extends Function
? T
: T extends object
? DeepReadonlyObject<T>
: T;
type DeepReadonlyArray<T> = ReadonlyArray<DeepReadonly<T>>;
type DeepReadonlyObject<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};

type FlagName =
| 'shortsToUsual'
| 'newTab'
Expand Down

0 comments on commit a469cde

Please sign in to comment.