pq module (v0.3.x)
pq provides query builders and reusable DOM matching helpers.
import { pq } from "@page-proxy/pp";
pq.selector(definition)
Builds reusable selector logic to identify elements easily and quickly.
Allows for use of other pq library methods and also provides multiple useful helper methods to control execution flow.
definition parameters:
nameMetadata label exposed onselector.definition.baseSelector(optional) Optional CSS prefilter. Trimmed; blank values fall back to"*".matches(element)Required predicate that decides whether an element matches.postMap(element)(optional) Optional transform for matched elements returned fromquery,queryAll,waitUntilMatch, andonElementMatches.
const premiumCards = pq.selector({
name: "premium-cards",
baseSelector: ".card",
matches: (el) => pq.innerTextMatches(el, /premium/i),
});
const first = premiumCards.query();
const all = premiumCards.queryAll();
const observer = premiumCards.onElementMatches((el) => {
console.log("New premium card:", el);
});
const nextMatch = await premiumCards.waitUntilMatch();
Available methods:
definition
Exposes the same object passed into pq.selector(definition).
Useful for reading selector metadata/configuration at runtime.
console.log(premiumCards.definition.name); // "premium-cards"
console.log(premiumCards.definition.baseSelector); // ".card"
matches(el)
Tests one element against your selector rules.
- checks
baseSelectorfirst (unless it resolves to"*") - runs your
matches(el)predicate - returns
trueorfalse
var candidate = document.querySelector(".card");
if (candidate && premiumCards.matches(candidate)) {
console.log("Candidate is a match");
}
query()
Returns the first current match from the document, or null when none match.
var firstMatch = premiumCards.query();
console.log("First match:", firstMatch);
queryAll()
Returns all current matches as an array.
var allMatches = premiumCards.queryAll();
console.log("Total matches:", allMatches.length);
waitUntilMatch(targetNode?, observerOptions?)
Returns a Promise that resolves when a matching element exists.
- first checks current DOM for an immediate match
- otherwise observes created elements until a match appears
- default options:
targetNode:document.body || document.documentElementobserverOptions:{ childList: true, subtree: true }
const match = await premiumCards.waitUntilMatch();
console.log("Resolved match:", match);
onElementMatches(func, targetNode, observerOptions)
Starts observing DOM insertions and runs func for matches.
- returns an
ElementCreatedObserver(built onMutationObserver) - runs once on the current subtree immediately
- continues for future added nodes
- default options:
targetNode:document.body || document.documentElementobserverOptions:{ childList: true, subtree: true }
var observer = premiumCards.onElementMatches(
function (value) {
console.log("Observed match:", value);
},
document.body,
{ childList: true, subtree: true },
);
observer.disconnect();
Match helpers
Supported helpers:
tagMatches: exact tag equality aftertrim().toLowerCase()selectorMatches: nativeElement.matcheswrapperinnerTextMatches: uses only direct text nodes (not descendant text); regex matchers removegbefore testingbboxMatches: compares left/top/right/bottom in page coordinates; default tolerance75propMatches/propContains/propExists: read special keys (tag,id,class,name,innerText,bbox) plus regular attributes
pq.tagMatches(el, "button");
pq.selectorMatches(el, ".cta.primary");
pq.innerTextMatches(el, "Upgrade");
pq.bboxMatches(el, { x: 100, y: 220, width: 280, height: 48 }, 25);
pq.propContains(el, "class", "featured");
Parent traversal
traverseParents(el, matcher, options?) walks from el.parentElement upward and returns the first match (or null).
const sectionId = pq.traverseParents(button, (parent) => parent.matches("section"), {
postMap: (parent) => parent.id,
});