all files / src/hyperscript/hasCssSelector/ matchPsuedoSelector.ts

48.98% Statements 24/49
35.56% Branches 16/45
60% Functions 3/5
46.67% Lines 21/45
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                                                                                                                 
import { VNode } from '../../'
 
const defaultParent = Object.freeze({ children: [] as Array<VNode> })
 
export function matchPsuedoSelector(cssSelector: string, vNode: VNode): boolean {
  const parent = vNode.parent || defaultParent
  const children = parent.children as Array<VNode>
 
  Iif (cssSelector.indexOf(`:nth-child`) === 0)
    return matchNthChild(cssSelector.slice(11).split(')')[0], vNode)
 
  if (cssSelector.indexOf(`:contains`) === 0)
    return vNodeContainsText(cssSelector.slice(10).split(')')[0], vNode)
 
  switch (cssSelector) {
  case ':first-child': return children && children[0] === vNode
  case ':last-child': return children && children[children.length - 1] === vNode
  case ':empty': return !vNode.children || vNode.children.length === 0
  case ':root': return isRoot(vNode)
  default: return false
  }
}
 
function vNodeContainsText(text: string, vNode: VNode) {
  if (vNode.text) return text === vNode.text
 
  const children = vNode.children
 
  if (!children || children.length === 0) return false
 
  for (let i = 0; i < children.length; ++i) {
    const child = children[i]
 
    Eif (child.text === text) return true
  }
 
  return false
}
 
function isRoot(vNode: VNode) {
  return !vNode.parent
}
 
function matchNthChild(index: string, vNode: VNode) {
  const parent = vNode.parent || defaultParent
  const children = parent.children
 
  if (!children || children.length === 0) return false
 
  if (index.indexOf('+') === -1 && !isNaN(parseInt(index, 10)))
    return children[parseInt(index, 10)] === vNode
 
  const childIndex = children.indexOf(vNode)
 
  if (index === 'odd')
    return childIndex % 2 !== 0
 
  if (index === 'even')
    return childIndex % 2 === 0
 
  if (index.indexOf('+') > -1) {
    const [ multipleString, offsetString ] = index.split('+')
    const multiple = parseInt(multipleString.split('n')[0], 10)
    const offset = parseInt(offsetString, 10)
 
    if (multiple === 0)
      return true
 
    return childIndex !== 0 && childIndex % (multiple + offset) === 0
  }
 
  return false
}
 
function isNaN(x: number): x is number {
  return (x | 0) !== x
}