Skip to content

Commit

Permalink
chore: split a cycle in BiDi (#11229)
Browse files Browse the repository at this point in the history
  • Loading branch information
OrKoN committed Oct 23, 2023
1 parent 525f13c commit 20eb38d
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 113 deletions.
133 changes: 133 additions & 0 deletions packages/puppeteer-core/src/bidi/Deserializer.ts
@@ -0,0 +1,133 @@
/**
* 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 type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';

import {debugError} from '../common/util.js';

/**
* @internal
*/
class UnsupportedTypeError extends Error {}

/**
* @internal
*/
export class BidiDeserializer {
static deserializeNumber(value: Bidi.Script.SpecialNumber | number): number {
switch (value) {
case '-0':
return -0;
case 'NaN':
return NaN;
case 'Infinity':
return Infinity;
case '-Infinity':
return -Infinity;
default:
return value;
}
}

static deserializeLocalValue(result: Bidi.Script.RemoteValue): unknown {
switch (result.type) {
case 'array':
if (result.value) {
return result.value.map(value => {
return BidiDeserializer.deserializeLocalValue(value);
});
}
break;
case 'set':
if (result.value) {
return result.value.reduce((acc: Set<unknown>, value) => {
return acc.add(BidiDeserializer.deserializeLocalValue(value));
}, new Set());
}
break;
case 'object':
if (result.value) {
return result.value.reduce((acc: Record<any, unknown>, tuple) => {
const {key, value} = BidiDeserializer.deserializeTuple(tuple);
acc[key as any] = value;
return acc;
}, {});
}
break;
case 'map':
if (result.value) {
return result.value?.reduce((acc: Map<unknown, unknown>, tuple) => {
const {key, value} = BidiDeserializer.deserializeTuple(tuple);
return acc.set(key, value);
}, new Map());
}
break;
case 'promise':
return {};
case 'regexp':
return new RegExp(result.value.pattern, result.value.flags);
case 'date':
return new Date(result.value);

case 'undefined':
return undefined;
case 'null':
return null;
case 'number':
return BidiDeserializer.deserializeNumber(result.value);
case 'bigint':
return BigInt(result.value);
case 'boolean':
return Boolean(result.value);
case 'string':
return result.value;
}

throw new UnsupportedTypeError(
`Deserialization of type ${result.type} not supported.`
);
}

static deserializeTuple([serializedKey, serializedValue]: [
Bidi.Script.RemoteValue | string,
Bidi.Script.RemoteValue,
]): {key: unknown; value: unknown} {
const key =
typeof serializedKey === 'string'
? serializedKey
: BidiDeserializer.deserializeLocalValue(serializedKey);
const value = BidiDeserializer.deserializeLocalValue(serializedValue);

return {key, value};
}

static deserialize(result: Bidi.Script.RemoteValue): any {
if (!result) {
debugError('Service did not produce a result.');
return undefined;
}

try {
return BidiDeserializer.deserializeLocalValue(result);
} catch (error) {
if (error instanceof UnsupportedTypeError) {
debugError(error.message);
return undefined;
}
throw error;
}
}
}
3 changes: 2 additions & 1 deletion packages/puppeteer-core/src/bidi/ExposedFunction.ts
Expand Up @@ -23,6 +23,7 @@ import {Deferred} from '../util/Deferred.js';
import {interpolateFunction, stringifyFunction} from '../util/Function.js';

import type {BidiConnection} from './Connection.js';
import {BidiDeserializer} from './Deserializer.js';
import type {BidiFrame} from './Frame.js';
import {BidiSerializer} from './Serializer.js';

Expand Down Expand Up @@ -142,7 +143,7 @@ export class ExposeableFunction<Args extends unknown[], Ret> {
const args = remoteValue.value?.[1];
assert(args);
try {
const result = await this.#apply(...BidiSerializer.deserialize(args));
const result = await this.#apply(...BidiDeserializer.deserialize(args));
await connection.send('script.callFunction', {
functionDeclaration: stringifyFunction(([_, resolve]: any, result) => {
resolve(result);
Expand Down
4 changes: 2 additions & 2 deletions packages/puppeteer-core/src/bidi/JSHandle.ts
Expand Up @@ -19,9 +19,9 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import type {ElementHandle} from '../api/ElementHandle.js';
import {JSHandle} from '../api/JSHandle.js';

import {BidiDeserializer} from './Deserializer.js';
import type {BidiRealm} from './Realm.js';
import type {Sandbox} from './Sandbox.js';
import {BidiSerializer} from './Serializer.js';
import {releaseReference} from './util.js';

/**
Expand Down Expand Up @@ -90,7 +90,7 @@ export class BidiJSHandle<T = unknown> extends JSHandle<T> {

override toString(): string {
if (this.isPrimitiveValue) {
return 'JSHandle:' + BidiSerializer.deserialize(this.#remoteValue);
return 'JSHandle:' + BidiDeserializer.deserialize(this.#remoteValue);
}

return 'JSHandle@' + this.#remoteValue.type;
Expand Down
4 changes: 2 additions & 2 deletions packages/puppeteer-core/src/bidi/Page.ts
Expand Up @@ -70,6 +70,7 @@ import {
type BrowsingContext,
} from './BrowsingContext.js';
import type {BidiConnection} from './Connection.js';
import {BidiDeserializer} from './Deserializer.js';
import {BidiDialog} from './Dialog.js';
import {BidiElementHandle} from './ElementHandle.js';
import {EmulationManager} from './EmulationManager.js';
Expand All @@ -80,7 +81,6 @@ import {BidiKeyboard, BidiMouse, BidiTouchscreen} from './Input.js';
import type {BidiJSHandle} from './JSHandle.js';
import {BidiNetworkManager} from './NetworkManager.js';
import {createBidiHandle} from './Realm.js';
import {BidiSerializer} from './Serializer.js';

/**
* @internal
Expand Down Expand Up @@ -399,7 +399,7 @@ export class BidiPage extends Page {
const text = args
.reduce((value, arg) => {
const parsedValue = arg.isPrimitiveValue
? BidiSerializer.deserialize(arg.remoteValue())
? BidiDeserializer.deserialize(arg.remoteValue())
: arg.toString();
return `${value} ${parsedValue}`;
}, '')
Expand Down
3 changes: 2 additions & 1 deletion packages/puppeteer-core/src/bidi/Realm.ts
Expand Up @@ -15,6 +15,7 @@ import {disposeSymbol} from '../util/disposable.js';
import {stringifyFunction} from '../util/Function.js';

import type {BidiConnection} from './Connection.js';
import {BidiDeserializer} from './Deserializer.js';
import {BidiElementHandle} from './ElementHandle.js';
import {BidiJSHandle} from './JSHandle.js';
import type {Sandbox} from './Sandbox.js';
Expand Down Expand Up @@ -195,7 +196,7 @@ export class BidiRealm extends EventEmitter<Record<EventType, any>> {
}

return returnByValue
? BidiSerializer.deserialize(result.result)
? BidiDeserializer.deserialize(result.result)
: createBidiHandle(sandbox, result.result);
}

Expand Down
106 changes: 1 addition & 105 deletions packages/puppeteer-core/src/bidi/Serializer.ts
Expand Up @@ -17,7 +17,7 @@
import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';

import {LazyArg} from '../common/LazyArg.js';
import {debugError, isDate, isPlainObject, isRegExp} from '../common/util.js';
import {isDate, isPlainObject, isRegExp} from '../common/util.js';

import {BidiElementHandle} from './ElementHandle.js';
import {BidiJSHandle} from './JSHandle.js';
Expand Down Expand Up @@ -172,108 +172,4 @@ export class BidiSerializer {

return BidiSerializer.serializeRemoteValue(arg);
}

static deserializeNumber(value: Bidi.Script.SpecialNumber | number): number {
switch (value) {
case '-0':
return -0;
case 'NaN':
return NaN;
case 'Infinity':
return Infinity;
case '-Infinity':
return -Infinity;
default:
return value;
}
}

static deserializeLocalValue(result: Bidi.Script.RemoteValue): unknown {
switch (result.type) {
case 'array':
if (result.value) {
return result.value.map(value => {
return BidiSerializer.deserializeLocalValue(value);
});
}
break;
case 'set':
if (result.value) {
return result.value.reduce((acc: Set<unknown>, value) => {
return acc.add(BidiSerializer.deserializeLocalValue(value));
}, new Set());
}
break;
case 'object':
if (result.value) {
return result.value.reduce((acc: Record<any, unknown>, tuple) => {
const {key, value} = BidiSerializer.deserializeTuple(tuple);
acc[key as any] = value;
return acc;
}, {});
}
break;
case 'map':
if (result.value) {
return result.value?.reduce((acc: Map<unknown, unknown>, tuple) => {
const {key, value} = BidiSerializer.deserializeTuple(tuple);
return acc.set(key, value);
}, new Map());
}
break;
case 'promise':
return {};
case 'regexp':
return new RegExp(result.value.pattern, result.value.flags);
case 'date':
return new Date(result.value);

case 'undefined':
return undefined;
case 'null':
return null;
case 'number':
return BidiSerializer.deserializeNumber(result.value);
case 'bigint':
return BigInt(result.value);
case 'boolean':
return Boolean(result.value);
case 'string':
return result.value;
}

throw new UnserializableError(
`Deserialization of type ${result.type} not supported.`
);
}

static deserializeTuple([serializedKey, serializedValue]: [
Bidi.Script.RemoteValue | string,
Bidi.Script.RemoteValue,
]): {key: unknown; value: unknown} {
const key =
typeof serializedKey === 'string'
? serializedKey
: BidiSerializer.deserializeLocalValue(serializedKey);
const value = BidiSerializer.deserializeLocalValue(serializedValue);

return {key, value};
}

static deserialize(result: Bidi.Script.RemoteValue): any {
if (!result) {
debugError('Service did not produce a result.');
return undefined;
}

try {
return BidiSerializer.deserializeLocalValue(result);
} catch (error) {
if (error instanceof UnserializableError) {
debugError(error.message);
return undefined;
}
throw error;
}
}
}
4 changes: 2 additions & 2 deletions packages/puppeteer-core/src/bidi/util.ts
Expand Up @@ -18,8 +18,8 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';

import {PuppeteerURL, debugError} from '../common/util.js';

import {BidiDeserializer} from './Deserializer.js';
import type {BidiRealm} from './Realm.js';
import {BidiSerializer} from './Serializer.js';

/**
* @internal
Expand Down Expand Up @@ -50,7 +50,7 @@ export function createEvaluationError(
details: Bidi.Script.ExceptionDetails
): unknown {
if (details.exception.type !== 'error') {
return BidiSerializer.deserialize(details.exception);
return BidiDeserializer.deserialize(details.exception);
}
const [name = '', ...parts] = details.text.split(': ');
const message = parts.join(': ');
Expand Down

0 comments on commit 20eb38d

Please sign in to comment.