all files / src/hyperscript/ h.ts

98.15% Statements 53/54
78.95% Branches 30/38
100% Functions 6/6
97.78% Lines 44/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 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    661× 661×   661× 661× 661×   661× 464×   464× 296× 197× 191×   191× 189× 108×     661×       661×   661×       661×   661×   661×     1116×   1116×     340× 170× 461×       170×     461×     170× 170×   170×   170× 460×   460× 450×   460×   460×     170×                                                                                
import { HtmlTagNames, SvgTagNames, VNode, VNodeProps } from '../types'
import { MostlyVNode, addSvgNamespace } from './VNode'
import { isPrimitive, isString } from '../helpers'
 
export const h: HyperscriptFn = function(): VNode {
  const tagName: string | ComponentFn = arguments[0] // required
  const childrenOrText: HyperscriptChildren = arguments[2] // optional
 
  let props: VNodeProps<Element> = {}
  let children: ArrayLike<VNode> | undefined
  let text: string | undefined
 
  if (childrenOrText) {
    props = arguments[1]
 
    if (isArrayLike(childrenOrText)) children = flattenArrayLike(childrenOrText) as Array<VNode>
    else Eif (isPrimitive(childrenOrText)) text = String(childrenOrText)
  } else if (arguments[1]) {
    const childrenOrTextOrProps = arguments[1]
 
    if (isArrayLike(childrenOrTextOrProps))
      children = flattenArrayLike(childrenOrTextOrProps) as Array<VNode>
    else if (isPrimitive(childrenOrTextOrProps)) text = String(childrenOrTextOrProps)
    else props = childrenOrTextOrProps
  }
 
  Iif (typeof tagName === 'function') {
    return tagName(props, Array.isArray(children) ? children : text ? [ text ] : [])
  }
 
  const isSvg = tagName === 'svg'
 
  const vNode = isSvg
    ? MostlyVNode.createSvg(tagName, props, undefined, text)
    : MostlyVNode.create(tagName, props, undefined, text)
 
  if (Array.isArray(children)) vNode.children = sanitizeChildren(children, vNode)
 
  if (isSvg) addSvgNamespace(vNode)
 
  return vNode
}
 
function isArrayLike<T>(x: any): x is ArrayLike<T> {
  const typeOf = typeof x
 
  return x && typeof x.length === 'number' && typeOf !== 'function' && typeOf !== 'string'
}
 
function flattenArrayLike<A>(arrayLike: ArrayLike<A | ArrayLike<A>>, Earr: Array<A> = []): Array<A> {
  forEach(
    (x: A | ArrayLike<A>) => (isArrayLike(x) ? flattenArrayLike(x, arr) : arr.push(x)),
    arrayLike
  )
 
  return arr
}
 
function forEach<A>(fn: (value: A) => void, list: ArrayLike<A>): void {
  for (let i = 0; i < list.length; ++i) fn(list[i])
}
 
function sanitizeChildren(childrenOrText: Array<VNode>, parent: VNode): Array<VNode> {
  childrenOrText = childrenOrText.filter(Boolean) // remove possible null values
  const childCount: number = childrenOrText.length
 
  const children: Array<VNode> = Array(childCount)
 
  for (let i = 0; i < childCount; ++i) {
    const vNodeOrText = childrenOrText[i]
 
    if (isString(vNodeOrText)) children[i] = MostlyVNode.createText(vNodeOrText)
    else children[i] = vNodeOrText
 
    if (parent.scope && !children[i].scope) children[i].scope = parent.scope
 
    children[i].parent = parent as VNode<Element>
  }
 
  return children
}
 
export type VNodeChildren = string | number | null | VNode
export type HyperscriptChildren =
  | VNodeChildren
  | ArrayLike<VNodeChildren>
  | ArrayLike<VNodeChildren | ArrayLike<VNodeChildren>>
  | ArrayLike<ArrayLike<VNodeChildren>>
 
export interface ComponentFn {
  (props: VNodeProps, children: Array<string | null | VNode>): VNode
}
 
export type ValidTagNames = HtmlTagNames | SvgTagNames | ComponentFn
 
export interface HyperscriptFn {
  (tagName: ValidTagNames): VNode
  (tagName: ValidTagNames, props: VNodeProps<any>): VNode
  (tagName: ValidTagNames, children: HyperscriptChildren): VNode
  (tagName: ValidTagNames, props: VNodeProps<any>, children: HyperscriptChildren): VNode
 
  <T extends Node, Props extends VNodeProps<Element> = VNodeProps<Element>>(
    tagName: ValidTagNames
  ): VNode<T, Props>
  <T extends Node, Props extends VNodeProps<Element> = VNodeProps<Element>>(
    tagName: ValidTagNames,
    props: Props
  ): VNode<T>
  <T extends Node, Props extends VNodeProps<Element> = VNodeProps<Element>>(
    tagName: ValidTagNames,
    children: HyperscriptChildren
  ): VNode<T, Props>
 
  <T extends Node, Props extends VNodeProps<Element> = VNodeProps<Element>>(
    tagName: ValidTagNames,
    props: Props,
    children: HyperscriptChildren
  ): VNode<T, Props>
}