UNPKG

chrome-devtools-frontend

Version:
99 lines (90 loc) 2.78 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /* eslint-disable rulesdir/es_modules_import */ import {type Selector} from './Selector.js'; import { findMinMax, SelectorRangeOps, type RangeOps, type QueryableNode, } from './CSSSelector.js'; import { pierceQuerySelectorAll, } from '../../../../third_party/puppeteer/package/lib/esm/puppeteer/injected/PierceQuerySelector.js'; class PierceSelectorRangeOpts implements RangeOps<QueryableNode, string[][]> { #selector: string[][] = [[]]; #attributes: string[]; #depth = 0; constructor(attributes: string[] = []) { this.#attributes = attributes; } inc(node: Node): Document|ShadowRoot { return node.getRootNode() as Document | ShadowRoot; } self(node: Document|ShadowRoot): QueryableNode { return node instanceof ShadowRoot ? node.host : node; } valueOf(node: QueryableNode): string[][] { const selector = findMinMax( [node, node.getRootNode()], new SelectorRangeOps(this.#attributes), ); if (this.#depth > 1) { this.#selector.unshift([selector]); } else { this.#selector[0].unshift(selector); } this.#depth = 0; return this.#selector; } gte(selector: string[][], node: Node): boolean { ++this.#depth; // Note we use some insider logic here. `valueOf(node)` will always // correspond to `selector.flat().slice(1)`, so it suffices to check // uniqueness for `selector.flat()[0]`. return pierceQuerySelectorAll(node, selector[0][0]).length === 1; } } /** * Computes the pierce CSS selector for a node. * * @param node - The node to compute. * @returns The computed pierce CSS selector. * * @internal */ export const computePierceSelector = ( node: Node, attributes?: string[], ): string[]|undefined => { try { const ops = new PierceSelectorRangeOpts(attributes); return findMinMax([node, document], ops).flat(); } catch { return undefined; } }; export const queryPierceSelectorAll = (selectors: Selector): Element[] => { if (typeof selectors === 'string') { selectors = [selectors]; } else if (selectors.length === 0) { return []; } let lists: Element[][] = [[document.documentElement]]; do { const selector = selectors.shift() as string; const roots: Element[][] = []; for (const nodes of lists) { for (const node of nodes) { const list = pierceQuerySelectorAll(node.shadowRoot ?? node, selector); if (list.length > 0) { roots.push(list); } } } lists = roots; } while (selectors.length > 0 && lists.length > 0); return lists.flatMap(list => [...list]); };