import { VNode } from './vnode';
import options from './options';
const stack = [];
const EMPTY_CHILDREN = [];
/**
* JSX/hyperscript reviver.
* @see http://jasonformat.com/wtf-is-jsx
* Benchmarks: https://esbench.com/bench/57ee8f8e330ab09900a1a1a0
*
* Note: this is exported as both `h()` and `createElement()` for compatibility
* reasons.
*
* Creates a VNode (virtual DOM element). A tree of VNodes can be used as a
* lightweight representation of the structure of a DOM tree. This structure can
* be realized by recursively comparing it against the current _actual_ DOM
* structure, and applying only the differences.
*
* `h()`/`createElement()` accepts an element name, a list of attributes/props,
* and optionally children to append to the element.
*
* @example The following DOM tree
*
* `
Hello!
`
*
* can be constructed using this function as:
*
* `h('div', { id: 'foo', name : 'bar' }, 'Hello!');`
*
* @param {string | function} nodeName An element name. Ex: `div`, `a`, `span`, etc.
* @param {object | null} attributes Any attributes/props to set on the created element.
* @param {VNode[]} [rest] Additional arguments are taken to be children to
* append. Can be infinitely nested Arrays.
*
* @public
*/
export function h(nodeName, attributes) {
let children=EMPTY_CHILDREN, lastSimple, child, simple, i;
for (i=arguments.length; i-- > 2; ) {
stack.push(arguments[i]);
}
if (attributes && attributes.children!=null) {
if (!stack.length) stack.push(attributes.children);
delete attributes.children;
}
while (stack.length) {
if ((child = stack.pop()) && child.pop!==undefined) {
for (i=child.length; i--; ) stack.push(child[i]);
}
else {
if (typeof child==='boolean') child = null;
if ((simple = typeof nodeName!=='function')) {
if (child==null) child = '';
else if (typeof child==='number') child = String(child);
else if (typeof child!=='string') simple = false;
}
if (simple && lastSimple) {
children[children.length-1] += child;
}
else if (children===EMPTY_CHILDREN) {
children = [child];
}
else {
children.push(child);
}
lastSimple = simple;
}
}
let p = new VNode();
p.nodeName = nodeName;
p.children = children;
p.attributes = attributes==null ? undefined : attributes;
p.key = attributes==null ? undefined : attributes.key;
// if a "vnode hook" is defined, pass every created VNode to it
if (options.vnode!==undefined) options.vnode(p);
return p;
}