diff --git a/.eslintrc.js b/.eslintrc.js index 90be582b..5a4bfa44 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -131,10 +131,7 @@ module.exports = { }, ], - 'import/no-cycle': [ - 'error', - {maxDepth: Infinity, allowUnsafeDynamicCyclicDependency: true}, - ], + 'import/no-cycle': ['error', {maxDepth: Infinity}], 'no-restricted-syntax': [ 'error', diff --git a/packages/puppeteer-core/src/api/ElementHandle.ts b/packages/puppeteer-core/src/api/ElementHandle.ts index f13bf53e..ca4fcd45 100644 --- a/packages/puppeteer-core/src/api/ElementHandle.ts +++ b/packages/puppeteer-core/src/api/ElementHandle.ts @@ -32,6 +32,7 @@ import {assert} from '../util/assert.js'; import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js'; import {throwIfDisposed} from '../util/decorators.js'; +import {_isElementHandle} from './ElementHandleSymbol.js'; import type { KeyboardTypeOptions, KeyPressOptions, @@ -149,6 +150,11 @@ export interface ElementScreenshotOptions extends ScreenshotOptions { export abstract class ElementHandle< ElementType extends Node = Element, > extends JSHandle { + /** + * @internal + */ + declare [_isElementHandle]: boolean; + /** * A given method will have it's `this` replaced with an isolated version of * `this` when decorated with this decorator. @@ -212,6 +218,7 @@ export abstract class ElementHandle< constructor(handle: JSHandle) { super(); this.handle = handle; + this[_isElementHandle] = true; } /** diff --git a/packages/puppeteer-core/src/api/ElementHandleSymbol.ts b/packages/puppeteer-core/src/api/ElementHandleSymbol.ts new file mode 100644 index 00000000..4bf8a472 --- /dev/null +++ b/packages/puppeteer-core/src/api/ElementHandleSymbol.ts @@ -0,0 +1,20 @@ +/** + * 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. + */ + +/** + * @internal + */ +export const _isElementHandle = Symbol('_isElementHandle'); diff --git a/packages/puppeteer-core/src/common/QueryHandler.ts b/packages/puppeteer-core/src/common/QueryHandler.ts index dc874c5e..7ce1f1fb 100644 --- a/packages/puppeteer-core/src/common/QueryHandler.ts +++ b/packages/puppeteer-core/src/common/QueryHandler.ts @@ -15,6 +15,7 @@ */ import type {ElementHandle} from '../api/ElementHandle.js'; +import {_isElementHandle} from '../api/ElementHandleSymbol.js'; import type {Frame} from '../api/Frame.js'; import type {WaitForSelectorOptions} from '../api/Page.js'; import type PuppeteerUtil from '../injected/injected.js'; @@ -132,8 +133,7 @@ export class QueryHandler { return context.puppeteerUtil; }) ); - const {ElementHandle} = await import('../api/ElementHandle.js'); - if (!(result instanceof ElementHandle)) { + if (!(_isElementHandle in result)) { return null; } return result.move(); @@ -151,10 +151,9 @@ export class QueryHandler { selector: string, options: WaitForSelectorOptions ): Promise | null> { - const {ElementHandle} = await import('../api/ElementHandle.js'); let frame!: Frame; using element = await (async () => { - if (!(elementOrFrame instanceof ElementHandle)) { + if (!(_isElementHandle in elementOrFrame)) { frame = elementOrFrame; return; } @@ -198,7 +197,7 @@ export class QueryHandler { throw signal.reason; } - if (!(handle instanceof ElementHandle)) { + if (!(_isElementHandle in handle)) { return null; } return await frame.mainRealm().transferHandle(handle);