text: /**
   * @file 组件预热
   * @author errorrik(errorrik@gmail.com)
   */
  
  var ExprType = require('../parser/expr-type');
  var each = require('../util/each');
  var createEl = require('../browser/create-el');
  var getPropHandler = require('./get-prop-handler');
  var getANodeProp = require('./get-a-node-prop');
  var isBrowser = require('../browser/is-browser');
  
  /**
   * 组件预热，分析组件aNode的数据引用等信息
   *
   * @param {Function} ComponentClass 组件类
   */
  function componentPreheat(ComponentClass) {
      var stack = [];
  
      function recordHotspotData(refs, notContentData) {
          var len = stack.length;
          each(stack, function (aNode, index) {
              if (!notContentData || index !== len - 1) {
                  each(refs, function (ref) {
                      aNode.hotspot.data[ref] = 1;
                  });
              }
          });
      }
  
  
      function analyseANodeHotspot(aNode) {
          if (!aNode.hotspot) {
              stack.push(aNode);
  
  
              if (aNode.textExpr) {
                  aNode.hotspot = {data: {}};
                  recordHotspotData(analyseExprDataHotspot(aNode.textExpr));
              }
              else {
                  var sourceNode;
                  if (isBrowser && aNode.tagName && !/^(template|slot|select|input|option)$/i.test(aNode.tagName)) {
                      sourceNode = createEl(aNode.tagName);
                  }
  
                  aNode.hotspot = {
                      data: {},
                      dynamicProps: [],
                      xProps: [],
                      props: {},
                      sourceNode: sourceNode
                  };
  
  
                  // === analyse hotspot data: start
                  each(aNode.vars, function (varItem) {
                      recordHotspotData(analyseExprDataHotspot(varItem.expr));
                  });
  
                  each(aNode.props, function (prop) {
                      recordHotspotData(analyseExprDataHotspot(prop.expr));
                  });
  
                  /* eslint-disable guard-for-in */
                  for (var key in aNode.directives) {
                      var directive = aNode.directives[key];
                      recordHotspotData(analyseExprDataHotspot(directive.value), key !== 'html');
                  }
                  /* eslint-enable guard-for-in */
  
                  each(aNode.elses, function (child) {
                      analyseANodeHotspot(child);
                  });
  
                  each(aNode.children, function (child) {
                      analyseANodeHotspot(child);
                  });
                  // === analyse hotspot data: end
  
  
                  // === analyse hotspot props: start
                  each(aNode.props, function (prop, index) {
                      aNode.hotspot.props[prop.name] = index;
  
                      if (prop.name === 'id') {
                          prop.id = true;
                          aNode.hotspot.idProp = prop;
                          aNode.hotspot.dynamicProps.push(prop);
                      }
                      else if (prop.expr.value != null) {
                          if (sourceNode) {
                              getPropHandler(aNode.tagName, prop.name)
                                  .prop(sourceNode, prop.expr.value, prop.name, aNode);
                          }
                      }
                      else {
                          if (prop.x) {
                              aNode.hotspot.xProps.push(prop);
                          }
                          aNode.hotspot.dynamicProps.push(prop);
                      }
                  });
  
                  // ie 下，如果 option 没有 value 属性，select.value = xx 操作不会选中 option
                  // 所以没有设置 value 时，默认把 option 的内容作为 value
                  if (aNode.tagName === 'option'
                      && !getANodeProp(aNode, 'value')
                      && aNode.children[0]
                  ) {
                      var valueProp = {
                          name: 'value',
                          expr: aNode.children[0].textExpr
                      };
                      aNode.props.push(valueProp);
                      aNode.hotspot.dynamicProps.push(valueProp);
                      aNode.hotspot.props.value = aNode.props.length - 1;
                  }
                  // === analyse hotspot props: end
              }
  
              stack.pop();
          }
      }
  
      analyseANodeHotspot(ComponentClass.prototype.aNode);
  }
  
  /**
   * 分析表达式的数据引用
   *
   * @param {Object} expr 要分析的表达式
   * @return {Array}
   */
  function analyseExprDataHotspot(expr) {
      var refs = [];
  
      function analyseExprs(exprs) {
          each(exprs, function (expr) {
              refs = refs.concat(analyseExprDataHotspot(expr));
          });
      }
  
      switch (expr.type) {
          case ExprType.ACCESSOR:
              var paths = expr.paths;
              refs.push(paths[0].value);
  
              if (paths.length > 1) {
                  refs.push(paths[0].value + '.' + (paths[1].value || '*'));
              }
  
              analyseExprs(paths.slice(1));
              break;
  
          case ExprType.UNARY:
              return analyseExprDataHotspot(expr.expr);
  
          case ExprType.TEXT:
          case ExprType.BINARY:
          case ExprType.TERTIARY:
              analyseExprs(expr.segs);
              break;
  
          case ExprType.INTERP:
              refs = analyseExprDataHotspot(expr.expr);
  
              each(expr.filters, function (filter) {
                  analyseExprs(filter.name.paths);
                  analyseExprs(filter.args);
              });
  
              break;
  
      }
  
      return refs;
  }
  
  exports = module.exports = componentPreheat;
  