text: import observable from 'riot-observable'
  import mkdom from './mkdom'
  import settings from '../../settings'
  import isSvg from './../common/util/checks/is-svg'
  import extend from './../common/util/misc/extend'
  import uid from './../common/util/misc/uid'
  import define from './../common/util/misc/define'
  import getTagName from './../common/util/tags/get-name'
  import componentUpdate from './component/update'
  import componentMixin from './component/mixin'
  import componentMount from './component/mount'
  import componentUnmount from './component/unmount'
  
  /**
   * Tag creation factory function
   * @constructor
   * @param { Object } impl - it contains the tag template, and logic
   * @param { Object } conf - tag options
   * @param { String } innerHTML - html that eventually we need to inject in the tag
   */
  export default function createTag(impl = {}, conf = {}, innerHTML) {
    const tag = conf.context || {}
    const opts = conf.opts || {}
    const parent = conf.parent
    const isLoop = conf.isLoop
    const isAnonymous = !!conf.isAnonymous
    const skipAnonymous = settings.skipAnonymousTags && isAnonymous
    const item = conf.item
    // available only for the looped nodes
    const index = conf.index
    // All attributes on the Tag when it's first parsed
    const instAttrs = []
    // expressions on this type of Tag
    const implAttrs = []
    const tmpl = impl.tmpl
    const expressions = []
    const root = conf.root
    const tagName = conf.tagName || getTagName(root)
    const isVirtual = tagName === 'virtual'
    const isInline = !isVirtual && !tmpl
    let dom
  
    if (isInline || isLoop && isAnonymous) {
      dom = root
    } else {
      if (!isVirtual) root.innerHTML = ''
      dom = mkdom(tmpl, innerHTML, isSvg(root))
    }
  
    // make this tag observable
    if (!skipAnonymous) observable(tag)
  
    // only call unmount if we have a valid __TAG_IMPL (has name property)
    if (impl.name && root._tag) root._tag.unmount(true)
  
    define(tag, '__', {
      impl,
      root,
      skipAnonymous,
      implAttrs,
      isAnonymous,
      instAttrs,
      innerHTML,
      tagName,
      index,
      isLoop,
      isInline,
      item,
      parent,
      // tags having event listeners
      // it would be better to use weak maps here but we can not introduce breaking changes now
      listeners: [],
      // these vars will be needed only for the virtual tags
      virts: [],
      wasCreated: false,
      tail: null,
      head: null
    })
  
    // tag protected properties
    return [
      ['isMounted', false],
      // create a unique id to this tag
      // it could be handy to use it also to improve the virtual dom rendering speed
      ['_riot_id', uid()],
      ['root', root],
      ['opts', opts, { writable: true, enumerable: true }],
      ['parent', parent || null],
      // protect the "tags" and "refs" property from being overridden
      ['tags', {}],
      ['refs', {}],
      ['update', data => componentUpdate(tag, data, expressions)],
      ['mixin', (...mixins) => componentMixin(tag, ...mixins)],
      ['mount', () => componentMount(tag, dom, expressions, opts)],
      ['unmount', mustKeepRoot => componentUnmount(tag, mustKeepRoot, expressions)]
    ].reduce((acc, [key, value, opts]) => {
      define(tag, key, value, opts)
      return acc
    }, extend(tag, item))
  }
  