[go: nahoru, domu]

blob: ff5ce22a6d1f08503a06d2e1f654d9ab795bdefb [file] [log] [blame]
// 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]);
};