Skip to content

Commit efdf595

Browse files
committed
add globals
1 parent 71213b0 commit efdf595

File tree

10 files changed

+167
-115
lines changed

10 files changed

+167
-115
lines changed

src/autoplay.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,19 @@ export class Autoplay extends BackgroundBehavior {
5353
while (run) {
5454
for (const [, elem] of querySelectorAllDeep(
5555
"video, audio, picture",
56-
).entries()) {
57-
interface AutoplayElement extends HTMLMediaElement {
58-
__bx_autoplay_found?: boolean;
59-
}
60-
if (!(elem as AutoplayElement)["__bx_autoplay_found"]) {
56+
).entries() as ArrayIterator<
57+
[number, HTMLVideoElement | HTMLAudioElement | HTMLPictureElement]
58+
>) {
59+
if (!elem["__bx_autoplay_found"]) {
6160
if (!this.running) {
6261
if (this.processFetchableUrl(elem as HTMLMediaElement)) {
63-
(elem as AutoplayElement)["__bx_autoplay_found"] = true;
62+
elem["__bx_autoplay_found"] = true;
6463
}
6564
continue;
6665
}
6766

6867
await this.loadMedia(elem as HTMLMediaElement);
69-
(elem as AutoplayElement)["__bx_autoplay_found"] = true;
68+
elem["__bx_autoplay_found"] = true;
7069
}
7170
}
7271

src/autoscroll.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { type AutoFetcher } from "./autofetcher";
1212

1313
// ===========================================================================
14-
export class AutoScroll extends Behavior {
14+
export class AutoScroll extends Behavior<{}, {}> {
1515
autoFetcher: AutoFetcher;
1616
showMoreQuery: string;
1717
state: { segments: number } = { segments: 1 };
@@ -57,7 +57,7 @@ export class AutoScroll extends Behavior {
5757
this.lastMsg = msg;
5858
}
5959

60-
hasScrollEL(obj) {
60+
hasScrollEL(obj: HTMLElement | Document | Window) {
6161
try {
6262
return !!self["getEventListeners"](obj).scroll;
6363
} catch (_) {
@@ -81,12 +81,12 @@ export class AutoScroll extends Behavior {
8181
return true;
8282
}
8383

84-
const lastScrollHeight = self.document.scrollingElement.scrollHeight;
84+
const lastScrollHeight = self.document.scrollingElement!.scrollHeight;
8585
const numFetching = this.autoFetcher.numFetching;
8686

8787
// scroll to almost end of page
8888
const scrollEnd =
89-
document.scrollingElement.scrollHeight * 0.98 - self.innerHeight;
89+
document.scrollingElement!.scrollHeight * 0.98 - self.innerHeight;
9090

9191
window.scrollTo({ top: scrollEnd, left: 0, behavior: "smooth" });
9292

@@ -95,7 +95,7 @@ export class AutoScroll extends Behavior {
9595

9696
// scroll height changed, should scroll
9797
if (
98-
lastScrollHeight !== self.document.scrollingElement.scrollHeight ||
98+
lastScrollHeight !== self.document.scrollingElement!.scrollHeight ||
9999
numFetching < this.autoFetcher.numFetching
100100
) {
101101
window.scrollTo({ top: 0, left: 0, behavior: "auto" });
@@ -112,7 +112,7 @@ export class AutoScroll extends Behavior {
112112

113113
if (
114114
(self.window.scrollY + self["scrollHeight"]) /
115-
self.document.scrollingElement.scrollHeight <
115+
self.document.scrollingElement!.scrollHeight <
116116
0.9
117117
) {
118118
return false;
@@ -194,7 +194,6 @@ export class AutoScroll extends Behavior {
194194
showMoreElem = null;
195195
}
196196

197-
// eslint-disable-next-line
198197
self.scrollBy(scrollOpts as ScrollToOptions);
199198

200199
await sleep(interval);
@@ -256,7 +255,6 @@ export class AutoScroll extends Behavior {
256255
lastScrollHeight = scrollHeight;
257256
}
258257

259-
// eslint-disable-next-line
260258
self.scrollBy(scrollOpts as ScrollToOptions);
261259

262260
await sleep(interval);

src/lib/behavior.ts

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ export class BackgroundBehavior {
1717
}
1818

1919
// ===========================================================================
20-
export class Behavior extends BackgroundBehavior {
20+
export class Behavior<State, Opts = EmptyObject>
21+
extends BackgroundBehavior
22+
implements AbstractBehavior<State, Opts>
23+
{
2124
_running: Promise<void> | null;
2225
paused: any;
2326
_unpause: any;
@@ -105,51 +108,66 @@ export class Behavior extends BackgroundBehavior {
105108
}
106109
}
107110

108-
async *[Symbol.asyncIterator]() {
111+
async *[Symbol.asyncIterator](): AsyncGenerator<
112+
State | undefined,
113+
void,
114+
void
115+
> {
109116
yield;
110117
}
111118
}
112119

113120
// WIP: BehaviorRunner class allows for arbitrary behaviors outside of the
114121
// library to be run through the BehaviorManager
115122

116-
export type Context<State, Opts> = {
123+
export type EmptyObject = Record<string, never>;
124+
125+
export type Context<State, Opts = EmptyObject> = {
117126
Lib: typeof Lib;
118127
state: State;
119128
opts: Opts;
120129
log: (data: any, type?: string) => Promise<void>;
121130
};
122131

123-
abstract class AbstractBehaviorInst<State, Opts, RunResult> {
124-
abstract run: (ctx: Context<State, Opts>) => AsyncIterable<RunResult | void>;
132+
export abstract class AbstractBehavior<State, Opts = EmptyObject> {
133+
static id: String;
134+
static isMatch: () => boolean;
135+
static init: () => any;
136+
137+
abstract run: (ctx: Context<State, Opts>) => AsyncIterable<any>;
125138

126139
abstract awaitPageLoad?: (ctx: Context<State, Opts>) => Promise<void>;
127140
}
128141

129-
interface StaticAbstractBehavior {
130-
id: string;
131-
isMatch: () => boolean;
132-
init: () => any;
133-
}
142+
type StaticProps<T> = {
143+
[K in keyof T]: T[K];
144+
};
134145

135-
export type AbstractBehavior<State, Opts, RunResult> =
136-
(new () => AbstractBehaviorInst<State, Opts, RunResult>) &
137-
StaticAbstractBehavior;
146+
type StaticBehaviorProps = StaticProps<typeof AbstractBehavior>;
138147

139-
export class BehaviorRunner<State, Opts, RunResult> extends BackgroundBehavior {
140-
inst: AbstractBehaviorInst<State, Opts, RunResult>;
141-
behaviorProps: StaticAbstractBehavior;
148+
// Non-abstract constructor type
149+
type ConcreteBehaviorConstructor<State, Opts> = StaticBehaviorProps & {
150+
new (): AbstractBehavior<State, Opts>;
151+
};
152+
153+
export class BehaviorRunner<
154+
State,
155+
Opts = EmptyObject,
156+
> extends BackgroundBehavior {
157+
inst: AbstractBehavior<State, Opts>;
158+
behaviorProps: ConcreteBehaviorConstructor<State, Opts>;
142159
ctx: Context<State, Opts>;
143-
_running: Promise<void> | null;
160+
_running: any;
144161
paused: any;
145-
_unpause: ((value?: unknown) => void) | null;
162+
_unpause: any;
146163

147164
get id() {
148-
return (this.inst.constructor as any).id;
165+
return (this.inst.constructor as ConcreteBehaviorConstructor<State, Opts>)
166+
.id;
149167
}
150168

151169
constructor(
152-
behavior: AbstractBehavior<State, Opts, RunResult>,
170+
behavior: ConcreteBehaviorConstructor<State, Opts>,
153171
mainOpts = {},
154172
) {
155173
super();
@@ -167,7 +185,7 @@ export class BehaviorRunner<State, Opts, RunResult> extends BackgroundBehavior {
167185
state = state || {};
168186
opts = opts ? { ...opts, ...mainOpts } : mainOpts;
169187
// eslint-disable-next-line @typescript-eslint/no-explicit-any
170-
const log = async (data: any, type: string) => this.wrappedLog(data, type);
188+
const log = async (data: any, type?: string) => this.wrappedLog(data, type);
171189

172190
this.ctx = { Lib, state, opts, log };
173191

@@ -194,7 +212,7 @@ export class BehaviorRunner<State, Opts, RunResult> extends BackgroundBehavior {
194212
this._running = this.run();
195213
}
196214

197-
async done() {
215+
done() {
198216
return this._running ? this._running : Promise.resolve();
199217
}
200218

src/lib/global.d.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { type BehaviorManager } from "..";
2+
3+
export {}; // Ensure this is treated as a module
4+
5+
interface BehaviorGlobals {
6+
__bx_addLink?: (url: string) => Promise<void>;
7+
__bx_fetch?: (url: string) => Promise<boolean>;
8+
__bx_addSet?: (url: string) => Promise<boolean>;
9+
__bx_netIdle?: (params: {
10+
idleTime: number;
11+
concurrency: number;
12+
}) => Promise<void>;
13+
__bx_initFlow?: (params: any) => Promise<number>;
14+
__bx_nextFlowStep?: (id: number) => Promise<any>;
15+
__bx_contentCheckFailed?: (reason: string) => void;
16+
__bx_open?: (params: { url: string | URL }) => Promise<void>;
17+
__bx_openResolve?: (window: WindowProxy | null) => void;
18+
__bx_behaviors?: BehaviorManager;
19+
}
20+
21+
interface AutoplayProperties {
22+
__bx_autoplay_found?: boolean;
23+
}
24+
25+
declare global {
26+
interface WorkerGlobalScope extends BehaviorGlobals {}
27+
interface Window extends BehaviorGlobals {
28+
__WB_replay_top?: Window;
29+
}
30+
31+
interface HTMLVideoElement extends AutoplayProperties {}
32+
interface HTMLAudioElement extends AutoplayProperties {}
33+
interface HTMLPictureElement extends AutoplayProperties {}
34+
}

src/lib/utils.ts

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type BehaviorManager } from "..";
22
import { type Context } from "./behavior";
33

4+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
45
let _logFunc: ((...data: any[]) => void) | null = console.log;
56
// @ts-expect-error TODO: what is this, and why is it declared twice, once here and once as a function?
67
let _behaviorMgrClass: (cls: typeof BehaviorManager) => void | null = null;
@@ -68,6 +69,7 @@ export async function awaitLoad(iframe?: HTMLIFrameElement) {
6869
});
6970
}
7071

72+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7173
function unsetToJson(obj: any) {
7274
if (obj.toJSON) {
7375
try {
@@ -79,6 +81,7 @@ function unsetToJson(obj: any) {
7981
}
8082
}
8183

84+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8285
function restoreToJson(obj: any) {
8386
if (obj.__bx__toJSON) {
8487
try {
@@ -91,40 +94,44 @@ function restoreToJson(obj: any) {
9194
}
9295

9396
function unsetAllJson() {
94-
unsetToJson(Object as any);
95-
unsetToJson(Object.prototype as any);
96-
unsetToJson(Array as any);
97-
unsetToJson(Array.prototype as any);
97+
unsetToJson(Object);
98+
unsetToJson(Object.prototype);
99+
unsetToJson(Array);
100+
unsetToJson(Array.prototype);
98101
}
99102

100103
function restoreAllJson() {
101-
restoreToJson(Object as any);
102-
restoreToJson(Object.prototype as any);
103-
restoreToJson(Array as any);
104-
restoreToJson(Array.prototype as any);
104+
restoreToJson(Object);
105+
restoreToJson(Object.prototype);
106+
restoreToJson(Array);
107+
restoreToJson(Array.prototype);
105108
}
106109

107110
let needUnsetToJson = false;
108111

112+
type WithToJSON<T> = T & {
113+
toJSON?: () => unknown;
114+
};
115+
109116
export function checkToJsonOverride() {
110117
needUnsetToJson =
111-
!!(Object as any).toJSON ||
112-
!!(Object.prototype as any).toJSON ||
113-
!!(Array as any).toJSON ||
114-
!!(Array.prototype as any).toJSON;
118+
!!(Object as WithToJSON<typeof Object>).toJSON ||
119+
!!(Object.prototype as WithToJSON<typeof Object.prototype>).toJSON ||
120+
!!(Array as WithToJSON<typeof Array>).toJSON ||
121+
!!(Array.prototype as WithToJSON<typeof Array.prototype>).toJSON;
115122
}
116123

117-
export async function callBinding(
118-
binding: (obj: any) => any,
119-
obj: any,
120-
): Promise<any> {
124+
export async function callBinding<P, R>(
125+
binding: (obj: P) => R,
126+
obj: P,
127+
): Promise<R> {
121128
try {
122129
if (needUnsetToJson) {
123130
unsetAllJson();
124131
}
125132
return binding(obj);
126133
} catch (_) {
127-
return binding(JSON.stringify(obj));
134+
return binding(JSON.stringify(obj) as P);
128135
} finally {
129136
if (needUnsetToJson) {
130137
restoreAllJson();
@@ -189,8 +196,8 @@ export function assertContentValid(
189196
) {
190197
if (typeof self["__bx_contentCheckFailed"] === "function") {
191198
if (!assertFunc()) {
192-
behaviorLog("Behavior content check failed: " + reason, "error");
193-
callBinding(self["__bx_contentCheckFailed"], reason);
199+
void behaviorLog("Behavior content check failed: " + reason, "error");
200+
void callBinding(self["__bx_contentCheckFailed"], reason);
194201
}
195202
}
196203
}
@@ -231,8 +238,7 @@ export function _behaviorMgrClass(cls: typeof BehaviorManager) {
231238
_behaviorMgrClass = cls;
232239
}
233240

234-
export function installBehaviors(obj: any) {
235-
// @ts-expect-error TODO: fix types here
241+
export function installBehaviors(obj: Window | WorkerGlobalScope) {
236242
obj.__bx_behaviors = new _behaviorMgrClass();
237243
}
238244

0 commit comments

Comments
 (0)