select-dom
Version:
Extra lightweight DOM selector helper
101 lines (100 loc) • 4.17 kB
JavaScript
// Type predicate for TypeScript
function isQueryable(object) {
return typeof object.querySelectorAll === 'function';
}
function $(selectors, baseElement) {
// Shortcut with specified-but-null baseElement
if (arguments.length === 2 && !baseElement) {
return;
}
return (baseElement ?? document).querySelector(String(selectors)) ?? undefined;
}
export class ElementNotFoundError extends Error {
name = 'ElementNotFoundError';
}
function expectElement(selectors, baseElement) {
// Shortcut with specified-but-null baseElement
if (arguments.length === 2 && !baseElement) {
throw new ElementNotFoundError('Expected element not found because the base is specified but null');
}
const element = (baseElement ?? document).querySelector(String(selectors));
if (element) {
return element;
}
throw new ElementNotFoundError(`Expected element not found: ${String(selectors)}`);
}
function lastElement(selectors, baseElement) {
// Shortcut with specified-but-null baseElement
if (arguments.length === 2 && !baseElement) {
return undefined;
}
const all = (baseElement ?? document).querySelectorAll(String(selectors));
// eslint-disable-next-line unicorn/prefer-at -- Not an Array, not worth converting it
return all[all.length - 1];
}
/**
* @param selectors One or more CSS selectors separated by commas
* @param [baseElement] The element to look inside of
* @return Whether it's been found
*/
function elementExists(selectors, baseElement) {
// Shortcut with specified-but-null baseElement
if (arguments.length === 2 && !baseElement) {
return false;
}
return Boolean((baseElement ?? document).querySelector(String(selectors)));
}
/**
* @param selectors One or more CSS selectors separated by commas
* @param [baseElement] The element to look inside of
* @return The number of elements found
*/
function countElements(selectors, baseElement) {
// Shortcut with specified-but-null baseElement
if (arguments.length === 2 && !baseElement) {
return 0;
}
return (baseElement ?? document).querySelectorAll(String(selectors)).length;
}
function $$(selectors, baseElements) {
// Shortcut with specified-but-null baseElements
if (arguments.length === 2 && !baseElements) {
return [];
}
// Can be: select.all('selectors') or select.all('selectors', singleElementOrDocument)
if (!baseElements || isQueryable(baseElements)) {
const elements = (baseElements ?? document).querySelectorAll(String(selectors));
return Array.prototype.slice.call(elements);
}
const elements = new Set();
for (const baseElement of baseElements) {
for (const element of baseElement.querySelectorAll(String(selectors))) {
elements.add(element);
}
}
return [...elements]; // Convert to array
}
function expectElements(selectors, baseElements) {
// Shortcut with specified-but-null baseElements
if (arguments.length === 2 && !baseElements) {
throw new ElementNotFoundError('Expected elements not found because the base is specified but null');
}
const elements = arguments.length === 2 ? $$(selectors, baseElements) : $$(selectors);
if (elements.length > 0) {
return elements;
}
throw new ElementNotFoundError(`Expected elements not found: ${String(selectors)}`);
}
function expectLastElement(selectors, baseElement) {
// Shortcut with specified-but-null baseElements
if (arguments.length === 2 && !baseElement) {
throw new ElementNotFoundError('Expected element not found because the base is specified but null');
}
const all = (baseElement ?? document).querySelectorAll(String(selectors));
if (all.length > 0) {
// eslint-disable-next-line unicorn/prefer-at -- Not an Array, not worth converting it
return all[all.length - 1];
}
throw new ElementNotFoundError(`Expected element not found: ${String(selectors)}`);
}
export { $, $$, lastElement, elementExists, countElements, expectElement, expectElements, expectLastElement, };