All files / utils selectDom.ts

52.38% Statements 11/21
66.67% Branches 20/30
80% Functions 4/5
52.38% Lines 11/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145                                                                        20x       20x                                                     6x         6x     6x                         7x       7x                                         8x         8x   8x     8x                                          
// https://github.com/fregante/select-dom/blob/master/index.ts
 
import { toArray, uniq } from 'lodash-uni'
import type { ParseSelector } from 'typed-query-selector/parser'
 
// WARNING: Overloads have to repeated in that fashion because the actual function’s signature is discarded; Only the 2 overloads are brought into the .d.ts file. Tests pass because `tsd` reads from this file instead of `.d.ts`
 
// ParentNode is inherited by Element, Document, DocumentFragment
type BaseElements = ParentNode | Iterable<ParentNode>
 
// Type predicate for TypeScript
function isQueryable(object: BaseElements): object is ParentNode {
  return typeof (object as any).querySelectorAll === 'function'
}
 
/**
 * @param selectors      One or more CSS selectors separated by commas
 * @param [baseElement]  The element to look inside of
 * @return               The element found, if any
 */
function selectElement<
  Selector extends string,
  TElement extends Element = ParseSelector<Selector, HTMLElement>,
>(
  selectors: Selector | Selector[],
  baseElement?: ParentNode,
): TElement | undefined
function selectElement<TElement extends Element = HTMLElement>(
  selectors: string | string[],
  baseElement?: ParentNode,
): TElement | undefined
function selectElement<TElement extends Element>(
  selectors: string | string[],
  baseElement?: ParentNode,
): TElement | undefined {
  // Shortcut with specified-but-null baseElement
  Iif (arguments.length === 2 && !baseElement) {
    return
  }
 
  return (
    (baseElement ?? document).querySelector<TElement>(String(selectors)) ??
    undefined
  )
}
 
/**
 * @param selectors      One or more CSS selectors separated by commas
 * @param [baseElement]  The element to look inside of
 * @return               The element found, if any
 */
function selectElementLast<
  Selector extends string,
  TElement extends Element = ParseSelector<Selector, HTMLElement>,
>(
  selectors: Selector | Selector[],
  baseElement?: ParentNode,
): TElement | undefined
function selectElementLast<TElement extends Element = HTMLElement>(
  selectors: string | string[],
  baseElement?: ParentNode,
): TElement | undefined
function selectElementLast<TElement extends Element>(
  selectors: string | string[],
  baseElement?: ParentNode,
): TElement | undefined {
  // Shortcut with specified-but-null baseElement
  Iif (arguments.length === 2 && !baseElement) {
    return undefined
  }
 
  // @ts-ignore
  const all = (baseElement ?? document).querySelectorAll<TElement>(
    String(selectors),
  )
  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 selectElementExists(
  selectors: string | string[],
  baseElement?: ParentNode,
): boolean {
  // Shortcut with specified-but-null baseElement
  Iif (arguments.length === 2 && !baseElement) {
    return false
  }
 
  return Boolean((baseElement ?? document).querySelector(String(selectors)))
}
 
/**
 * @param selectors       One or more CSS selectors separated by commas
 * @param [baseElements]  The element or list of elements to look inside of
 * @return                An array of elements found
 */
function selectElementAll<
  Selector extends string,
  TElement extends Element = ParseSelector<Selector, HTMLElement>,
>(selectors: Selector | Selector[], baseElements?: BaseElements): TElement[]
function selectElementAll<TElement extends Element = HTMLElement>(
  selectors: string | string[],
  baseElements?: BaseElements,
): TElement[]
function selectElementAll<TElement extends Element>(
  selectors: string | string[],
  baseElements?: BaseElements,
): TElement[] {
  // Shortcut with specified-but-null baseElements
  Iif (arguments.length === 2 && !baseElements) {
    return []
  }
 
  // Can be: select.all('selectors') or select.all('selectors', singleElementOrDocument)
  if (!baseElements || isQueryable(baseElements)) {
    // @ts-ignore
    const elements = (baseElements ?? document).querySelectorAll<TElement>(
      String(selectors),
    )
    return toArray(elements)
  }
 
  const queried: TElement[] = []
  for (const baseElement of baseElements) {
    for (const element of toArray(
      baseElement.querySelectorAll<TElement>(String(selectors)),
    )) {
      queried.push(element)
    }
  }
 
  return uniq(queried)
}
 
export {
  selectElement,
  selectElementLast,
  selectElementExists,
  selectElementAll,
}