mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
118 lines
3.3 KiB
TypeScript
118 lines
3.3 KiB
TypeScript
import {JSHandle} from '../api/JSHandle.js';
|
|
import {isErrorLike} from '../util/ErrorLike.js';
|
|
|
|
import {type ExecutionContext} from './ExecutionContext.js';
|
|
import {debugError} from './util.js';
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
export class Binding {
|
|
#name: string;
|
|
#fn: (...args: unknown[]) => unknown;
|
|
constructor(name: string, fn: (...args: unknown[]) => unknown) {
|
|
this.#name = name;
|
|
this.#fn = fn;
|
|
}
|
|
|
|
get name(): string {
|
|
return this.#name;
|
|
}
|
|
|
|
/**
|
|
* @param context - Context to run the binding in; the context should have
|
|
* the binding added to it beforehand.
|
|
* @param id - ID of the call. This should come from the CDP
|
|
* `onBindingCalled` response.
|
|
* @param args - Plain arguments from CDP.
|
|
*/
|
|
async run(
|
|
context: ExecutionContext,
|
|
id: number,
|
|
args: unknown[],
|
|
isTrivial: boolean
|
|
): Promise<void> {
|
|
const stack = new DisposableStack();
|
|
try {
|
|
if (!isTrivial) {
|
|
// Getting non-trivial arguments.
|
|
using handles = await context.evaluateHandle(
|
|
(name, seq) => {
|
|
// @ts-expect-error Code is evaluated in a different context.
|
|
return globalThis[name].args.get(seq);
|
|
},
|
|
this.#name,
|
|
id
|
|
);
|
|
const properties = await handles.getProperties();
|
|
for (const [index, handle] of properties) {
|
|
// This is not straight-forward since some arguments can stringify, but
|
|
// aren't plain objects so add subtypes when the use-case arises.
|
|
if (index in args) {
|
|
switch (handle.remoteObject().subtype) {
|
|
case 'node':
|
|
args[+index] = handle;
|
|
break;
|
|
default:
|
|
stack.use(handle);
|
|
}
|
|
} else {
|
|
stack.use(handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
await context.evaluate(
|
|
(name, seq, result) => {
|
|
// @ts-expect-error Code is evaluated in a different context.
|
|
const callbacks = globalThis[name].callbacks;
|
|
callbacks.get(seq).resolve(result);
|
|
callbacks.delete(seq);
|
|
},
|
|
this.#name,
|
|
id,
|
|
await this.#fn(...args)
|
|
);
|
|
|
|
for (const arg of args) {
|
|
if (arg instanceof JSHandle) {
|
|
stack.use(arg);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (isErrorLike(error)) {
|
|
await context
|
|
.evaluate(
|
|
(name, seq, message, stack) => {
|
|
const error = new Error(message);
|
|
error.stack = stack;
|
|
// @ts-expect-error Code is evaluated in a different context.
|
|
const callbacks = globalThis[name].callbacks;
|
|
callbacks.get(seq).reject(error);
|
|
callbacks.delete(seq);
|
|
},
|
|
this.#name,
|
|
id,
|
|
error.message,
|
|
error.stack
|
|
)
|
|
.catch(debugError);
|
|
} else {
|
|
await context
|
|
.evaluate(
|
|
(name, seq, error) => {
|
|
// @ts-expect-error Code is evaluated in a different context.
|
|
const callbacks = globalThis[name].callbacks;
|
|
callbacks.get(seq).reject(error);
|
|
callbacks.delete(seq);
|
|
},
|
|
this.#name,
|
|
id,
|
|
error
|
|
)
|
|
.catch(debugError);
|
|
}
|
|
}
|
|
}
|
|
}
|