mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: extract BiDi context to allow emitting only to it (#9742)
This commit is contained in:
parent
ed1bb7cbe0
commit
4a365a42b4
@ -103,13 +103,11 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
|
|||||||
this.#connection.on('sessiondetached', this.#onSessionDetached);
|
this.#connection.on('sessiondetached', this.#onSessionDetached);
|
||||||
this.#setupAttachmentListeners(this.#connection);
|
this.#setupAttachmentListeners(this.#connection);
|
||||||
|
|
||||||
// TODO: remove `as any` once the protocol definitions are updated with the
|
|
||||||
// next Chromium roll.
|
|
||||||
this.#connection
|
this.#connection
|
||||||
.send('Target.setDiscoverTargets', {
|
.send('Target.setDiscoverTargets', {
|
||||||
discover: true,
|
discover: true,
|
||||||
filter: [{type: 'tab', exclude: true}, {}],
|
filter: [{type: 'tab', exclude: true}, {}],
|
||||||
} as any)
|
})
|
||||||
.then(this.#storeExistingTargetsForInit)
|
.then(this.#storeExistingTargetsForInit)
|
||||||
.catch(debugError);
|
.catch(debugError);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
import * as BidiMapper from 'chromium-bidi/lib/cjs/bidiMapper/bidiMapper.js';
|
import * as BidiMapper from 'chromium-bidi/lib/cjs/bidiMapper/bidiMapper.js';
|
||||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
import type {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
|
import type {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
|
||||||
|
@ -18,6 +18,7 @@ import {BrowserContext as BrowserContextBase} from '../../api/BrowserContext.js'
|
|||||||
import {Page as PageBase} from '../../api/Page.js';
|
import {Page as PageBase} from '../../api/Page.js';
|
||||||
|
|
||||||
import {Connection} from './Connection.js';
|
import {Connection} from './Connection.js';
|
||||||
|
import {Context} from './Context.js';
|
||||||
import {Page} from './Page.js';
|
import {Page} from './Page.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,10 +33,11 @@ export class BrowserContext extends BrowserContextBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async newPage(): Promise<PageBase> {
|
override async newPage(): Promise<PageBase> {
|
||||||
const response = await this.#connection.send('browsingContext.create', {
|
const {result} = await this.#connection.send('browsingContext.create', {
|
||||||
type: 'tab',
|
type: 'tab',
|
||||||
});
|
});
|
||||||
return new Page(this.#connection, response.result.context);
|
const context = this.#connection.context(result.context) as Context;
|
||||||
|
return new Page(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async close(): Promise<void> {}
|
override async close(): Promise<void> {}
|
||||||
|
@ -22,6 +22,8 @@ import {debug} from '../Debug.js';
|
|||||||
import {ProtocolError} from '../Errors.js';
|
import {ProtocolError} from '../Errors.js';
|
||||||
import {EventEmitter} from '../EventEmitter.js';
|
import {EventEmitter} from '../EventEmitter.js';
|
||||||
|
|
||||||
|
import {Context} from './Context.js';
|
||||||
|
|
||||||
const debugProtocolSend = debug('puppeteer:webDriverBiDi:SEND ►');
|
const debugProtocolSend = debug('puppeteer:webDriverBiDi:SEND ►');
|
||||||
const debugProtocolReceive = debug('puppeteer:webDriverBiDi:RECV ◀');
|
const debugProtocolReceive = debug('puppeteer:webDriverBiDi:RECV ◀');
|
||||||
|
|
||||||
@ -78,6 +80,7 @@ export class Connection extends EventEmitter {
|
|||||||
#lastId = 0;
|
#lastId = 0;
|
||||||
#closed = false;
|
#closed = false;
|
||||||
#callbacks: Map<number, ConnectionCallback> = new Map();
|
#callbacks: Map<number, ConnectionCallback> = new Map();
|
||||||
|
#contexts: Map<string, Context> = new Map();
|
||||||
|
|
||||||
constructor(transport: ConnectionTransport, delay = 0) {
|
constructor(transport: ConnectionTransport, delay = 0) {
|
||||||
super();
|
super();
|
||||||
@ -92,6 +95,10 @@ export class Connection extends EventEmitter {
|
|||||||
return this.#closed;
|
return this.#closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context(contextId: string): Context | null {
|
||||||
|
return this.#contexts.get(contextId) || null;
|
||||||
|
}
|
||||||
|
|
||||||
send<T extends keyof Commands>(
|
send<T extends keyof Commands>(
|
||||||
method: T,
|
method: T,
|
||||||
params: Commands[T]['params']
|
params: Commands[T]['params']
|
||||||
@ -126,7 +133,8 @@ export class Connection extends EventEmitter {
|
|||||||
debugProtocolReceive(message);
|
debugProtocolReceive(message);
|
||||||
const object = JSON.parse(message) as
|
const object = JSON.parse(message) as
|
||||||
| Bidi.Message.CommandResponse
|
| Bidi.Message.CommandResponse
|
||||||
| Bidi.EventResponse<string, unknown>;
|
| Bidi.Message.EventMessage;
|
||||||
|
|
||||||
if ('id' in object) {
|
if ('id' in object) {
|
||||||
const callback = this.#callbacks.get(object.id);
|
const callback = this.#callbacks.get(object.id);
|
||||||
// Callbacks could be all rejected if someone has called `.dispose()`.
|
// Callbacks could be all rejected if someone has called `.dispose()`.
|
||||||
@ -137,10 +145,21 @@ export class Connection extends EventEmitter {
|
|||||||
createProtocolError(callback.error, callback.method, object)
|
createProtocolError(callback.error, callback.method, object)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
if (callback.method === 'browsingContext.create') {
|
||||||
|
this.#contexts.set(
|
||||||
|
object.result.context,
|
||||||
|
new Context(this, object.result.context)
|
||||||
|
);
|
||||||
|
}
|
||||||
callback.resolve(object);
|
callback.resolve(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if ('source' in object.params && !!object.params.source.context) {
|
||||||
|
const context = this.#contexts.get(object.params.source.context);
|
||||||
|
context?.emit(object.method, object.params);
|
||||||
|
}
|
||||||
|
|
||||||
this.emit(object.method, object.params);
|
this.emit(object.method, object.params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
140
packages/puppeteer-core/src/common/bidi/Context.ts
Normal file
140
packages/puppeteer-core/src/common/bidi/Context.ts
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
|
import {stringifyFunction} from '../../util/Function.js';
|
||||||
|
import {EventEmitter} from '../EventEmitter.js';
|
||||||
|
import {EvaluateFunc, HandleFor} from '../types.js';
|
||||||
|
import {isString} from '../util.js';
|
||||||
|
|
||||||
|
import {Connection} from './Connection.js';
|
||||||
|
import {JSHandle} from './JSHandle.js';
|
||||||
|
import {BidiSerializer} from './Serializer.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export class Context extends EventEmitter {
|
||||||
|
#connection: Connection;
|
||||||
|
_contextId: string;
|
||||||
|
|
||||||
|
constructor(connection: Connection, contextId: string) {
|
||||||
|
super();
|
||||||
|
this.#connection = connection;
|
||||||
|
this._contextId = contextId;
|
||||||
|
}
|
||||||
|
|
||||||
|
get connection(): Connection {
|
||||||
|
return this.#connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
get id(): string {
|
||||||
|
return this._contextId;
|
||||||
|
}
|
||||||
|
|
||||||
|
async evaluateHandle<
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
||||||
|
>(
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
|
||||||
|
return this.#evaluate(false, pageFunction, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
async evaluate<
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
||||||
|
>(
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
|
return this.#evaluate(true, pageFunction, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #evaluate<
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
||||||
|
>(
|
||||||
|
returnByValue: true,
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<Awaited<ReturnType<Func>>>;
|
||||||
|
async #evaluate<
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
||||||
|
>(
|
||||||
|
returnByValue: false,
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<HandleFor<Awaited<ReturnType<Func>>>>;
|
||||||
|
async #evaluate<
|
||||||
|
Params extends unknown[],
|
||||||
|
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
||||||
|
>(
|
||||||
|
returnByValue: boolean,
|
||||||
|
pageFunction: Func | string,
|
||||||
|
...args: Params
|
||||||
|
): Promise<HandleFor<Awaited<ReturnType<Func>>> | Awaited<ReturnType<Func>>> {
|
||||||
|
let responsePromise;
|
||||||
|
const resultOwnership = returnByValue ? 'none' : 'root';
|
||||||
|
if (isString(pageFunction)) {
|
||||||
|
responsePromise = this.#connection.send('script.evaluate', {
|
||||||
|
expression: pageFunction,
|
||||||
|
target: {context: this._contextId},
|
||||||
|
resultOwnership,
|
||||||
|
awaitPromise: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
responsePromise = this.#connection.send('script.callFunction', {
|
||||||
|
functionDeclaration: stringifyFunction(pageFunction),
|
||||||
|
arguments: await Promise.all(
|
||||||
|
args.map(arg => {
|
||||||
|
return BidiSerializer.serialize(arg, this);
|
||||||
|
})
|
||||||
|
),
|
||||||
|
target: {context: this._contextId},
|
||||||
|
resultOwnership,
|
||||||
|
awaitPromise: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const {result} = await responsePromise;
|
||||||
|
|
||||||
|
if ('type' in result && result.type === 'exception') {
|
||||||
|
throw new Error(result.exceptionDetails.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnByValue
|
||||||
|
? BidiSerializer.deserialize(result.result)
|
||||||
|
: getBidiHandle(this, result.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function getBidiHandle(
|
||||||
|
context: Context,
|
||||||
|
result: Bidi.CommonDataTypes.RemoteValue
|
||||||
|
): JSHandle {
|
||||||
|
if ((result.type === 'node' || result.type === 'window') && context) {
|
||||||
|
// TODO: Implement ElementHandle
|
||||||
|
return new JSHandle(context, result);
|
||||||
|
}
|
||||||
|
return new JSHandle(context, result);
|
||||||
|
}
|
@ -21,7 +21,7 @@ import {JSHandle as BaseJSHandle} from '../../api/JSHandle.js';
|
|||||||
import {EvaluateFuncWith, HandleFor, HandleOr} from '../../common/types.js';
|
import {EvaluateFuncWith, HandleFor, HandleOr} from '../../common/types.js';
|
||||||
|
|
||||||
import {Connection} from './Connection.js';
|
import {Connection} from './Connection.js';
|
||||||
import {Page} from './Page.js';
|
import {Context} from './Context.js';
|
||||||
import {BidiSerializer} from './Serializer.js';
|
import {BidiSerializer} from './Serializer.js';
|
||||||
import {releaseReference} from './utils.js';
|
import {releaseReference} from './utils.js';
|
||||||
|
|
||||||
@ -30,17 +30,17 @@ export class JSHandle<T = unknown> extends BaseJSHandle<T> {
|
|||||||
#context;
|
#context;
|
||||||
#remoteValue;
|
#remoteValue;
|
||||||
|
|
||||||
constructor(context: Page, remoteValue: Bidi.CommonDataTypes.RemoteValue) {
|
constructor(context: Context, remoteValue: Bidi.CommonDataTypes.RemoteValue) {
|
||||||
super();
|
super();
|
||||||
this.#context = context;
|
this.#context = context;
|
||||||
this.#remoteValue = remoteValue;
|
this.#remoteValue = remoteValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
context(): Page {
|
context(): Context {
|
||||||
return this.#context;
|
return this.#context;
|
||||||
}
|
}
|
||||||
|
|
||||||
get connecton(): Connection {
|
get connection(): Connection {
|
||||||
return this.#context.connection;
|
return this.#context.connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ export class JSHandle<T = unknown> extends BaseJSHandle<T> {
|
|||||||
}
|
}
|
||||||
this.#disposed = true;
|
this.#disposed = true;
|
||||||
if ('handle' in this.#remoteValue) {
|
if ('handle' in this.#remoteValue) {
|
||||||
await releaseReference(this.connecton, this.#remoteValue);
|
await releaseReference(this.#context, this.#remoteValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ export class JSHandle<T = unknown> extends BaseJSHandle<T> {
|
|||||||
return 'handle' in this.#remoteValue ? this.#remoteValue.handle : undefined;
|
return 'handle' in this.#remoteValue ? this.#remoteValue.handle : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
bidiObject(): Bidi.CommonDataTypes.RemoteValue {
|
remoteValue(): Bidi.CommonDataTypes.RemoteValue {
|
||||||
return this.#remoteValue;
|
return this.#remoteValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,49 +17,46 @@
|
|||||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
import {Page as PageBase, PageEmittedEvents} from '../../api/Page.js';
|
import {Page as PageBase, PageEmittedEvents} from '../../api/Page.js';
|
||||||
import {stringifyFunction} from '../../util/Function.js';
|
|
||||||
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
|
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
|
||||||
import type {EvaluateFunc, HandleFor} from '../types.js';
|
import {EvaluateFunc, HandleFor} from '../types.js';
|
||||||
import {isString} from '../util.js';
|
|
||||||
|
|
||||||
import {Connection} from './Connection.js';
|
import {Connection} from './Connection.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {Context, getBidiHandle} from './Context.js';
|
||||||
import {BidiSerializer} from './Serializer.js';
|
import {BidiSerializer} from './Serializer.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export class Page extends PageBase {
|
export class Page extends PageBase {
|
||||||
#connection: Connection;
|
#context: Context;
|
||||||
#subscribedEvents = [
|
#subscribedEvents = [
|
||||||
'log.entryAdded',
|
'log.entryAdded',
|
||||||
] as Bidi.Session.SubscribeParameters['events'];
|
] as Bidi.Session.SubscribeParameters['events'];
|
||||||
_contextId: string;
|
#boundOnLogEntryAdded = this.#onLogEntryAdded.bind(this);
|
||||||
|
|
||||||
constructor(connection: Connection, contextId: string) {
|
constructor(context: Context) {
|
||||||
super();
|
super();
|
||||||
this.#connection = connection;
|
this.#context = context;
|
||||||
this._contextId = contextId;
|
|
||||||
|
|
||||||
// TODO: Investigate an implementation similar to CDPSession
|
// TODO: Investigate an implementation similar to CDPSession
|
||||||
this.connection.send('session.subscribe', {
|
this.connection.send('session.subscribe', {
|
||||||
events: this.#subscribedEvents,
|
events: this.#subscribedEvents,
|
||||||
contexts: [this._contextId],
|
contexts: [this.contextId],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.connection.on('log.entryAdded', this.#onLogEntryAdded.bind(this));
|
this.#context.on('log.entryAdded', this.#boundOnLogEntryAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
#onLogEntryAdded(event: Bidi.Log.LogEntry): void {
|
#onLogEntryAdded(event: Bidi.Log.LogEntry): void {
|
||||||
if (isConsoleLogEntry(event)) {
|
if (isConsoleLogEntry(event)) {
|
||||||
const args = event.args.map(arg => {
|
const args = event.args.map(arg => {
|
||||||
return getBidiHandle(this, arg);
|
return getBidiHandle(this.#context, arg);
|
||||||
});
|
});
|
||||||
|
|
||||||
const text = args
|
const text = args
|
||||||
.reduce((value, arg) => {
|
.reduce((value, arg) => {
|
||||||
const parsedValue = arg.isPrimitiveValue
|
const parsedValue = arg.isPrimitiveValue
|
||||||
? BidiSerializer.deserialize(arg.bidiObject())
|
? BidiSerializer.deserialize(arg.remoteValue())
|
||||||
: arg.toString();
|
: arg.toString();
|
||||||
return `${value} ${parsedValue}`;
|
return `${value} ${parsedValue}`;
|
||||||
}, '')
|
}, '')
|
||||||
@ -88,20 +85,24 @@ export class Page extends PageBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async close(): Promise<void> {
|
override async close(): Promise<void> {
|
||||||
await this.#connection.send('browsingContext.close', {
|
await this.connection.send('session.unsubscribe', {
|
||||||
context: this._contextId,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.connection.send('session.unsubscribe', {
|
|
||||||
events: this.#subscribedEvents,
|
events: this.#subscribedEvents,
|
||||||
contexts: [this._contextId],
|
contexts: [this.contextId],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.connection.off('log.entryAdded', this.#onLogEntryAdded.bind(this));
|
await this.connection.send('browsingContext.close', {
|
||||||
|
context: this.contextId,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#context.off('log.entryAdded', this.#boundOnLogEntryAdded);
|
||||||
}
|
}
|
||||||
|
|
||||||
get connection(): Connection {
|
get connection(): Connection {
|
||||||
return this.#connection;
|
return this.#context.connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
get contextId(): string {
|
||||||
|
return this.#context.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
override async evaluateHandle<
|
override async evaluateHandle<
|
||||||
@ -111,7 +112,7 @@ export class Page extends PageBase {
|
|||||||
pageFunction: Func | string,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
|
): Promise<HandleFor<Awaited<ReturnType<Func>>>> {
|
||||||
return this.#evaluate(false, pageFunction, ...args);
|
return this.#context.evaluateHandle(pageFunction, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async evaluate<
|
override async evaluate<
|
||||||
@ -121,83 +122,8 @@ export class Page extends PageBase {
|
|||||||
pageFunction: Func | string,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): Promise<Awaited<ReturnType<Func>>> {
|
): Promise<Awaited<ReturnType<Func>>> {
|
||||||
return this.#evaluate(true, pageFunction, ...args);
|
return this.#context.evaluate(pageFunction, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
async #evaluate<
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
|
||||||
>(
|
|
||||||
returnByValue: true,
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<Awaited<ReturnType<Func>>>;
|
|
||||||
async #evaluate<
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
|
||||||
>(
|
|
||||||
returnByValue: false,
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<HandleFor<Awaited<ReturnType<Func>>>>;
|
|
||||||
async #evaluate<
|
|
||||||
Params extends unknown[],
|
|
||||||
Func extends EvaluateFunc<Params> = EvaluateFunc<Params>
|
|
||||||
>(
|
|
||||||
returnByValue: boolean,
|
|
||||||
pageFunction: Func | string,
|
|
||||||
...args: Params
|
|
||||||
): Promise<HandleFor<Awaited<ReturnType<Func>>> | Awaited<ReturnType<Func>>> {
|
|
||||||
let responsePromise;
|
|
||||||
const resultOwnership = returnByValue ? 'none' : 'root';
|
|
||||||
if (isString(pageFunction)) {
|
|
||||||
responsePromise = this.#connection.send('script.evaluate', {
|
|
||||||
expression: pageFunction,
|
|
||||||
target: {context: this._contextId},
|
|
||||||
resultOwnership,
|
|
||||||
awaitPromise: true,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
responsePromise = this.#connection.send('script.callFunction', {
|
|
||||||
functionDeclaration: stringifyFunction(pageFunction),
|
|
||||||
arguments: await Promise.all(
|
|
||||||
args.map(arg => {
|
|
||||||
return BidiSerializer.serialize(arg, this);
|
|
||||||
})
|
|
||||||
),
|
|
||||||
target: {context: this._contextId},
|
|
||||||
resultOwnership,
|
|
||||||
awaitPromise: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const {result} = await responsePromise;
|
|
||||||
|
|
||||||
if ('type' in result && result.type === 'exception') {
|
|
||||||
throw new Error(result.exceptionDetails.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnByValue
|
|
||||||
? BidiSerializer.deserialize(result.result)
|
|
||||||
: getBidiHandle(this, result.result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export function getBidiHandle(
|
|
||||||
context: Page,
|
|
||||||
result: Bidi.CommonDataTypes.RemoteValue
|
|
||||||
): JSHandle {
|
|
||||||
if (
|
|
||||||
(result.type === 'node' || result.type === 'window') &&
|
|
||||||
context._contextId
|
|
||||||
) {
|
|
||||||
// TODO: Implement ElementHandle
|
|
||||||
return new JSHandle(context, result);
|
|
||||||
}
|
|
||||||
return new JSHandle(context, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isConsoleLogEntry(
|
function isConsoleLogEntry(
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||||
|
|
||||||
import {debugError, isDate, isPlainObject, isRegExp} from '../util.js';
|
import {debugError, isDate, isPlainObject, isRegExp} from '../util.js';
|
||||||
|
|
||||||
|
import {Context} from './Context.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
import {Page} from './Page.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -130,7 +146,7 @@ export class BidiSerializer {
|
|||||||
|
|
||||||
static serialize(
|
static serialize(
|
||||||
arg: unknown,
|
arg: unknown,
|
||||||
context: Page
|
context: Context
|
||||||
): Bidi.CommonDataTypes.LocalOrRemoteValue {
|
): Bidi.CommonDataTypes.LocalOrRemoteValue {
|
||||||
// TODO: See use case of LazyArgs
|
// TODO: See use case of LazyArgs
|
||||||
const objectHandle = arg && arg instanceof JSHandle ? arg : null;
|
const objectHandle = arg && arg instanceof JSHandle ? arg : null;
|
||||||
@ -143,7 +159,7 @@ export class BidiSerializer {
|
|||||||
if (objectHandle.disposed) {
|
if (objectHandle.disposed) {
|
||||||
throw new Error('JSHandle is disposed!');
|
throw new Error('JSHandle is disposed!');
|
||||||
}
|
}
|
||||||
return objectHandle.bidiObject();
|
return objectHandle.remoteValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
return BidiSerializer.serializeRemoveValue(arg);
|
return BidiSerializer.serializeRemoveValue(arg);
|
||||||
|
@ -18,7 +18,7 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
|||||||
|
|
||||||
import {debug} from '../Debug.js';
|
import {debug} from '../Debug.js';
|
||||||
|
|
||||||
import {Connection} from './Connection.js';
|
import {Context} from './Context.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -28,15 +28,15 @@ export const debugError = debug('puppeteer:error');
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export async function releaseReference(
|
export async function releaseReference(
|
||||||
client: Connection,
|
client: Context,
|
||||||
remoteReference: Bidi.CommonDataTypes.RemoteReference
|
remoteReference: Bidi.CommonDataTypes.RemoteReference
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!remoteReference.handle) {
|
if (!remoteReference.handle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await client
|
await client.connection
|
||||||
.send('script.disown', {
|
.send('script.disown', {
|
||||||
target: {realm: '', context: ''}, // TODO: Populate
|
target: {context: client._contextId},
|
||||||
handles: [remoteReference.handle],
|
handles: [remoteReference.handle],
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user