text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  
  var _babelTraverse = require('babel-traverse');
  
  var _babelTraverse2 = _interopRequireDefault(_babelTraverse);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  /**
   * Utility for AST.
   */
  class ASTUtil {
    /**
     * sanitize node.
     * change node type to `Identifier` and empty comment.
     * @param {ASTNode} node - target node.
     */
    static sanitize(node) {
      if (!node) return;
      node.type = 'Identifier';
      node.name = '_';
      node.leadingComments = [];
      node.trailingComments = [];
    }
  
    /**
     * traverse ast nodes.
     * @param {AST} ast - target AST.
     * @param {function(node: Object, parent: Object, path: Object)} callback - this is called with each node.
     */
    static traverse(ast, callback) {
      (0, _babelTraverse2.default)(ast, {
        noScope: true,
        enter: function (path) {
          callback(path.node, path.parent, path);
        }
      });
    }
  
    /**
     * find file path in import declaration by name.
     * e.g. can find ``./foo/bar.js`` from ``import Bar from './foo/bar.js'`` by ``Bar``.
     * @param {AST} ast - target AST.
     * @param {string} name - identifier name.
     * @returns {string|null} file path.
     */
    static findPathInImportDeclaration(ast, name) {
      let path = null;
  
      (0, _babelTraverse2.default)(ast, {
        noScope: true,
        enter: function (_path) {
          const node = _path.node;
          if (node.type !== 'ImportDeclaration') return;
  
          for (const spec of node.specifiers) {
            const localName = spec.local.name;
            if (localName === name) {
              path = node.source.value;
              _path.stop();
            }
          }
        }
      });
  
      return path;
    }
  
    /**
     * find VariableDeclaration node which has NewExpression.
     * @param {string} name - variable name.
     * @param {AST} ast - find in this ast.
     * @returns {ASTNode|null} found ast node.
     */
    static findVariableDeclarationAndNewExpressionNode(name, ast) {
      if (!name) return null;
  
      for (const node of ast.program.body) {
        if (node.type === 'VariableDeclaration' && node.declarations[0].init && node.declarations[0].init.type === 'NewExpression' && node.declarations[0].id.name === name) {
          return node;
        }
      }
  
      return null;
    }
  
    /**
     * find ClassDeclaration node.
     * @param {string} name - class name.
     * @param {AST} ast - find in this ast.
     * @returns {{classNode: ASTNode|null, exported: boolean|null}} found ast node.
     */
    static findClassDeclarationNode(name, ast) {
      if (!name) return { classNode: null, exported: null };
  
      for (const node of ast.program.body) {
        if (node.type === 'ClassDeclaration' && node.id.name === name) return { classNode: node, exported: false };
  
        if (node.type === 'ExportDefaultDeclaration' || node.type === 'ExportNamedDeclaration') {
          if (node.declaration && node.declaration.type === 'ClassDeclaration' && node.declaration.id && node.declaration.id.name === name) return { classNode: node, exported: true };
        }
      }
  
      return { classNode: null, exported: null };
    }
  
    /**
     * find FunctionDeclaration node.
     * @param {string} name - function name.
     * @param {AST} ast - find in this ast.
     * @returns {ASTNode|null} found ast node.
     */
    static findFunctionDeclarationNode(name, ast) {
      if (!name) return null;
  
      for (const node of ast.program.body) {
        if (node.type === 'FunctionDeclaration' && node.id.name === name) return node;
      }
  
      return null;
    }
  
    /**
     * find VariableDeclaration node.
     * @param {string} name - variable name.
     * @param {AST} ast - find in this ast.
     * @returns {ASTNode|null} found ast node.
     */
    static findVariableDeclarationNode(name, ast) {
      if (!name) return null;
  
      for (const node of ast.program.body) {
        if (node.type === 'VariableDeclaration' && node.declarations[0].id.name === name) return node;
      }
  
      return null;
    }
  
    /**
     * create VariableDeclaration node which has NewExpression.
     * @param {string} name - variable name.
     * @param {string} className - class name.
     * @param {Object} loc - location.
     * @returns {ASTNode} created node.
     */
    static createVariableDeclarationAndNewExpressionNode(name, className, loc) {
      const node = {
        type: 'VariableDeclaration',
        kind: 'let',
        loc: loc,
        declarations: [{
          type: 'VariableDeclarator',
          id: { type: 'Identifier', name: name },
          init: { type: 'NewExpression', callee: { type: 'Identifier', name: className } }
        }]
      };
  
      return node;
    }
  
    // /**
    //  * flatten name of MemberExpression.
    //  * @param {ASTNode} memberExpression - MemberExpression Node.
    //  * @returns {string} flatten node name.
    //  */
    // static flattenMemberExpression(memberExpression) {
    //   const names = [];
    //   let object = memberExpression;
    //   while (object) {
    //     if (object.name) {
    //       names.push(object.name);
    //       break;
    //     } else {
    //       names.push(object.property.name);
    //       object = object.object;
    //     }
    //   }
    //   return names.reverse().join('.');
    // }
  }
  exports.default = ASTUtil;