chore: move query selectors to injection script (#8980)

This commit is contained in:
jrandolf 2022-09-19 13:22:10 +02:00 committed by GitHub
parent dda85944b8
commit 5a4eb38083
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 136 additions and 82 deletions

View File

@ -197,91 +197,29 @@ const defaultHandler = createPuppeteerQueryHandler({
}); });
const pierceHandler = createPuppeteerQueryHandler({ const pierceHandler = createPuppeteerQueryHandler({
queryOne: (element, selector) => { queryOne: (element, selector, {pierceQuerySelector}) => {
let found: Node | null = null; return pierceQuerySelector(element, selector);
const search = (root: Node) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode as HTMLElement;
if (currentNode.shadowRoot) {
search(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (currentNode !== root && !found && currentNode.matches(selector)) {
found = currentNode;
}
} while (!found && iter.nextNode());
};
if (element instanceof Document) {
element = element.documentElement;
}
search(element);
return found;
}, },
queryAll: (element, selector, {pierceQuerySelectorAll}) => {
queryAll: (element, selector) => { return pierceQuerySelectorAll(element, selector);
const result: Node[] = [];
const collect = (root: Node) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode as HTMLElement;
if (currentNode.shadowRoot) {
collect(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (currentNode !== root && currentNode.matches(selector)) {
result.push(currentNode);
}
} while (iter.nextNode());
};
if (element instanceof Document) {
element = element.documentElement;
}
collect(element);
return result;
}, },
}); });
const xpathHandler = createPuppeteerQueryHandler({ const xpathHandler = createPuppeteerQueryHandler({
queryOne: (element, selector) => { queryOne: (element, selector, {xpathQuerySelector}) => {
const doc = element.ownerDocument || document; return xpathQuerySelector(element, selector);
const result = doc.evaluate(
selector,
element,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE
);
return result.singleNodeValue;
}, },
queryAll: (element, selector, {xpathQuerySelectorAll}) => {
queryAll: (element, selector) => { return xpathQuerySelectorAll(element, selector);
const doc = element.ownerDocument || document;
const iterator = doc.evaluate(
selector,
element,
null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE
);
const array: Node[] = [];
let item;
while ((item = iterator.iterateNext())) {
array.push(item);
}
return array;
}, },
}); });
const textQueryHandler = createPuppeteerQueryHandler({ const textQueryHandler = createPuppeteerQueryHandler({
queryOne: (element, selector, {textQuerySelector}) => { queryOne: (element, selector, {textQuerySelector}) => {
return textQuerySelector(selector, element); return textQuerySelector(element, selector);
}, },
queryAll: (element, selector, {textQuerySelectorAll}) => { queryAll: (element, selector, {textQuerySelectorAll}) => {
return textQuerySelectorAll(selector, element); return textQuerySelectorAll(element, selector);
}, },
}); });

View File

@ -0,0 +1,67 @@
// Copyright 2022 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.
export const pierceQuerySelector = (
root: Node,
selector: string
): Element | null => {
let found: Node | null = null;
const search = (root: Node) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode as Element;
if (currentNode.shadowRoot) {
search(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (currentNode !== root && !found && currentNode.matches(selector)) {
found = currentNode;
}
} while (!found && iter.nextNode());
};
if (root instanceof Document) {
root = root.documentElement;
}
search(root);
return found;
};
export const pierceQuerySelectorAll = (
element: Node,
selector: string
): Element[] => {
const result: Element[] = [];
const collect = (root: Node) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode as Element;
if (currentNode.shadowRoot) {
collect(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (currentNode !== root && currentNode.matches(selector)) {
result.push(currentNode);
}
} while (iter.nextNode());
};
if (element instanceof Document) {
element = element.documentElement;
}
collect(element);
return result;
};

View File

@ -25,16 +25,16 @@ import {
* @internal * @internal
*/ */
export const textQuerySelector = ( export const textQuerySelector = (
selector: string, root: Node,
root: Node selector: string
): Element | null => { ): Element | null => {
for (const node of root.childNodes) { for (const node of root.childNodes) {
if (node instanceof Element && isSuitableNodeForTextMatching(node)) { if (node instanceof Element && isSuitableNodeForTextMatching(node)) {
let matchedNode: Element | null; let matchedNode: Element | null;
if (node.shadowRoot) { if (node.shadowRoot) {
matchedNode = textQuerySelector(selector, node.shadowRoot); matchedNode = textQuerySelector(node.shadowRoot, selector);
} else { } else {
matchedNode = textQuerySelector(selector, node); matchedNode = textQuerySelector(node, selector);
} }
if (matchedNode) { if (matchedNode) {
return matchedNode; return matchedNode;
@ -57,17 +57,17 @@ export const textQuerySelector = (
* @internal * @internal
*/ */
export const textQuerySelectorAll = ( export const textQuerySelectorAll = (
selector: string, root: Node,
root: Node selector: string
): Element[] => { ): Element[] => {
let results: Element[] = []; let results: Element[] = [];
for (const node of root.childNodes) { for (const node of root.childNodes) {
if (node instanceof Element) { if (node instanceof Element) {
let matchedNodes: Element[]; let matchedNodes: Element[];
if (node.shadowRoot) { if (node.shadowRoot) {
matchedNodes = textQuerySelectorAll(selector, node.shadowRoot); matchedNodes = textQuerySelectorAll(node.shadowRoot, selector);
} else { } else {
matchedNodes = textQuerySelectorAll(selector, node); matchedNodes = textQuerySelectorAll(node, selector);
} }
results = results.concat(matchedNodes); results = results.concat(matchedNodes);
} }

View File

@ -0,0 +1,45 @@
/**
* Copyright 2022 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.
*/
export const xpathQuerySelector = (
root: Node,
selector: string
): Node | null => {
const doc = root.ownerDocument || document;
const result = doc.evaluate(
selector,
root,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE
);
return result.singleNodeValue;
};
export const xpathQuerySelectorAll = (root: Node, selector: string): Node[] => {
const doc = root.ownerDocument || document;
const iterator = doc.evaluate(
selector,
root,
null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE
);
const array: Node[] = [];
let item;
while ((item = iterator.iterateNext())) {
array.push(item);
}
return array;
};

View File

@ -17,14 +17,18 @@
import {createDeferredPromise} from '../util/DeferredPromise.js'; import {createDeferredPromise} from '../util/DeferredPromise.js';
import * as Poller from './Poller.js'; import * as Poller from './Poller.js';
import * as TextContent from './TextContent.js'; import * as TextContent from './TextContent.js';
import * as TextSelector from './TextSelector.js'; import * as TextQuerySelector from './TextQuerySelector.js';
import * as XPathQuerySelector from './XPathQuerySelector.js';
import * as PierceQuerySelector from './PierceQuerySelector.js';
import * as util from './util.js'; import * as util from './util.js';
const PuppeteerUtil = Object.freeze({ const PuppeteerUtil = Object.freeze({
...util, ...util,
...Poller, ...Poller,
...TextContent, ...TextContent,
...TextSelector, ...TextQuerySelector,
...XPathQuerySelector,
...PierceQuerySelector,
createDeferredPromise, createDeferredPromise,
}); });