diff --git a/packages/puppeteer-core/src/injected/PQuerySelector.ts b/packages/puppeteer-core/src/injected/PQuerySelector.ts index 57f65d9a..07b30245 100644 --- a/packages/puppeteer-core/src/injected/PQuerySelector.ts +++ b/packages/puppeteer-core/src/injected/PQuerySelector.ts @@ -170,6 +170,10 @@ class PQueryEngine { } } +type QueryableNode = { + querySelectorAll: typeof Document.prototype.querySelectorAll; +}; + /** * Queries the given node for all nodes matching the given text selector. * @@ -180,8 +184,9 @@ export const pQuerySelectorAll = async function* ( selector: string ): AwaitableIterable { let selectors: ComplexPSelectorList; + let isPureCSS: boolean; try { - selectors = parsePSelectors(selector); + [selectors, isPureCSS] = parsePSelectors(selector); } catch (error) { if (!isErrorLike(error)) { throw new SelectorError(selector, String(error)); @@ -189,6 +194,11 @@ export const pQuerySelectorAll = async function* ( throw new SelectorError(selector, error.message); } + if (isPureCSS) { + yield* (root as unknown as QueryableNode).querySelectorAll(selector); + return; + } + // If there are any empty elements, then this implies the selector has // contiguous combinators (e.g. `>>> >>>>`) or starts/ends with one which we // treat as illegal, similar to existing behavior. diff --git a/packages/puppeteer-core/src/injected/PSelectorParser.ts b/packages/puppeteer-core/src/injected/PSelectorParser.ts index d0c3d371..7efe50a2 100644 --- a/packages/puppeteer-core/src/injected/PSelectorParser.ts +++ b/packages/puppeteer-core/src/injected/PSelectorParser.ts @@ -75,10 +75,13 @@ const unquote = (text: string): string => { return text; }; -export function parsePSelectors(selector: string): ComplexPSelectorList { +export function parsePSelectors( + selector: string +): [selector: ComplexPSelectorList, isPureCSS: boolean] { + let isPureCSS = true; const tokens = tokenize(selector); if (tokens.length === 0) { - return []; + return [[], isPureCSS]; } let compoundSelector: CompoundPSelector = []; let complexSelector: ComplexPSelector = [compoundSelector]; @@ -89,6 +92,7 @@ export function parsePSelectors(selector: string): ComplexPSelectorList { case 'combinator': switch (token.content) { case '>>>': + isPureCSS = false; if (storage.length) { compoundSelector.push(storage.toStringAndClear()); } @@ -97,6 +101,7 @@ export function parsePSelectors(selector: string): ComplexPSelectorList { complexSelector.push(compoundSelector); continue; case '>>>>': + isPureCSS = false; if (storage.length) { compoundSelector.push(storage.toStringAndClear()); } @@ -110,6 +115,7 @@ export function parsePSelectors(selector: string): ComplexPSelectorList { if (!token.name.startsWith('-p-')) { break; } + isPureCSS = false; if (storage.length) { compoundSelector.push(storage.toStringAndClear()); } @@ -132,5 +138,5 @@ export function parsePSelectors(selector: string): ComplexPSelectorList { if (storage.length) { compoundSelector.push(storage.toStringAndClear()); } - return selectors; + return [selectors, isPureCSS]; }