text: /* @flow */
  
  import VNode, { createTextVNode } from 'core/vdom/vnode'
  import { isFalse, isTrue, isDef, isUndef, isPrimitive } from 'shared/util'
  
  // The template compiler attempts to minimize the need for normalization by
  // statically analyzing the template at compile time.
  //
  // For plain HTML markup, normalization can be completely skipped because the
  // generated render function is guaranteed to return Array<VNode>. There are
  // two cases where extra normalization is needed:
  
  // 1. When the children contains components - because a functional component
  // may return an Array instead of a single root. In this case, just a simple
  // normalization is needed - if any child is an Array, we flatten the whole
  // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
  // because functional components already normalize their own children.
  // 当子组件包含组件时—因为功能组件可能返回一个Array而不是单个根。 在这种情况下
  // ，只需要一个简单的标准化——如果任何子元素是Array，我们就用Array.prototype.concat将整个东西平铺开来。
  // 它保证只有1级深度，因为功能组件已经规范化了它们自己的子组件。
  export function simpleNormalizeChildren (children: any) {
    for (let i = 0; i < children.length; i++) {
      if (Array.isArray(children[i])) {
        return Array.prototype.concat.apply([], children)
      }
    }
    return children
  }
  
  // 2. When the children contains constructs that always generated nested Arrays,
  // e.g. <template>, <slot>, v-for, or when the children is provided by user
  // with hand-written render functions / JSX. In such cases a full normalization
  // is needed to cater to all possible types of children values.
  // 当子元素包含总是生成嵌套数组的构造时，例如<template>， <slot>， v-for，或者当子元素
  // 由用户用手写的呈现函数/ JSX提供时。 在这种情况下，需要完全规范化，迎合所有可能类型的 child 的值
  export function normalizeChildren (children: any): ?Array<VNode> {
    return isPrimitive(children)
      ? [createTextVNode(children)]
      : Array.isArray(children)
        ? normalizeArrayChildren(children)
        : undefined
  }
  
  function isTextNode (node): boolean {
    return isDef(node) && isDef(node.text) && isFalse(node.isComment)
  }
  
  //  `normalizeArrayChildren` 主要的逻辑就是遍历 `children`，获得单个节点 `c`，然后对 `c` 的类型判断，
  // 如果是一个数组类型，则递归调用 `normalizeArrayChildren`; 如果是基础类型，则通过 `createTextVNode` 方法转换成 VNode 类型；
  // 否则就已经是 VNode 类型了，如果 `children` 是一个列表并且列表还存在嵌套的情况，则根据 `nestedIndex` 去更新它的 key。
  // 这里需要注意一点，在遍历的过程中，对这 3 种情况都做了如下处理：如果存在两个连续的 `text` 节点，会把它们合并成一个 `text` 节点。
  function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
    const res = []
    let i, c, lastIndex, last
    for (i = 0; i < children.length; i++) {
      c = children[i]
      if (isUndef(c) || typeof c === 'boolean') continue
      lastIndex = res.length - 1
      last = res[lastIndex]
      //  nested
      if (Array.isArray(c)) {
        if (c.length > 0) {
          c = normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`)
          // merge adjacent text nodes
          if (isTextNode(c[0]) && isTextNode(last)) {
            res[lastIndex] = createTextVNode(last.text + (c[0]: any).text)
            c.shift()
          }
          res.push.apply(res, c)
        }
      } else if (isPrimitive(c)) {
        if (isTextNode(last)) {
          // merge adjacent text nodes
          // this is necessary for SSR hydration because text nodes are
          // essentially merged when rendered to HTML strings
          res[lastIndex] = createTextVNode(last.text + c)
        } else if (c !== '') {
          // convert primitive to vnode
          res.push(createTextVNode(c))
        }
      } else {
        if (isTextNode(c) && isTextNode(last)) {
          // merge adjacent text nodes
          res[lastIndex] = createTextVNode(last.text + c.text)
        } else {
          // default key for nested array children (likely generated by v-for)
          if (isTrue(children._isVList) &&
            isDef(c.tag) &&
            isUndef(c.key) &&
            isDef(nestedIndex)) {
            c.key = `__vlist${nestedIndex}_${i}__`
          }
          res.push(c)
        }
      }
    }
    return res
  }
  