All files index.ts

99.09% Statements 110/111
100% Branches 43/43
75% Functions 3/4
99.09% Lines 110/111

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  1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 10x 10x 10x 10x 5x 5x 5x 1x 1x 59x 59x 58x 59x 59x 59x 59x 59x 59x 61x 61x 56x 49x 49x 49x 1x 1x 1x 1x 1x 5x 5x 5x 61x 61x 58x 58x 59x 53x 53x 53x 59x 23x 21x 21x 23x 23x 23x 5x 5x 5x 16x 23x 16x 23x 16x 23x 23x 53x 59x 59x 59x 59x 59x 59x 47x 47x 53x 59x 59x  
/// <reference path="../jsx.d.ts" />
 
import { Properties as CSSProperties } from 'csstype'
 
type CSSPropertyNames = keyof CSSProperties
 
export type Element = Function | { children: Child[] } | keyof HTMLElementTagNameMap | string
export type Props = {
  style?: { [property in CSSPropertyNames]?: string | number }
  [attribute: string]: any
}
export type Child = string | boolean | number | null
export type PropsWithChildren<T> = T & {
  children?: Child | Child[]
}
 
const aliases = {
  className: 'class',
  htmlFor: 'for',
}
 
const voids = [
  'area',
  'base',
  'br',
  'col',
  'embed',
  'hr',
  'img',
  'input',
  'link',
  'meta',
  'param',
  'source',
  'track',
  'wbr',
]
 
export function styleObjectToString(style: { [property in CSSPropertyNames]: string | number }) {
  let s = ''
 
  for (const p in style) {
    const k = p.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
    const v = style[p]
    if (v || typeof v === 'number') s += k + ':' + style[p] + ';'
  }
 
  return s
}
 
export function h(tag: Element, props: Props, ...children: Child[] | Child[][]): string {
  // multiple children as immediate children
  if (typeof tag === 'object' && tag.children) return tag.children.join('')
 
  props = props || {}
 
  const c = []
  children = children.length ? children : props.children || []
 
  while (children.length) {
    const child = children.shift()
    if (!child) continue
    switch (typeof child) {
      case 'string':
        c.push(child)
        break
      case 'number':
        c.push(`${child}`)
        break
      case 'boolean':
        continue
      default:
        // @ts-expect-error
        children.push(...child)
    }
  }
 
  // needed for JSX
  if (typeof tag === 'function') return tag({ ...props, children: c })
 
  let attrs = ''
 
  for (const k of Object.keys(props)) {
    if (k === 'children') continue
 
    let value = props[k]
    const key = aliases[k] || k
 
    if (typeof value === 'boolean' || value === '') {
      attrs += `${key} `
      continue
    }
 
    if (value === 0) value += ''
 
    if (k === 'style') value = styleObjectToString(value)
 
    if (value) attrs += `${key}="${value}"`
  }
 
  const a = attrs ? ' ' + attrs.trim() : ''
  const v = voids.indexOf(tag as string) > -1
 
  let childs = ''
 
  while (c.length) {
    childs += c.shift()
  }
 
  return v ? '<' + tag + a + ' />' : '<' + tag + a + '>' + childs + '</' + tag + '>'
}