'use strict';

var _es6Map = require('es6-map');

var _es6Map2 = _interopRequireDefault(_es6Map);

var _getExports = require('../core/getExports');

var _getExports2 = _interopRequireDefault(_getExports);

var _declaredScope = require('../core/declaredScope');

var _declaredScope2 = _interopRequireDefault(_declaredScope);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

module.exports = function (context) {
  var deprecated = new _es6Map2.default(),
      namespaces = new _es6Map2.default();

  function checkSpecifiers(node) {
    if (node.type !== 'ImportDeclaration') return;
    if (node.source == null) return; // local export, ignore

    var imports = _getExports2.default.get(node.source.value, context);
    if (imports == null) return;

    var moduleDeprecation = void 0;
    if (imports.doc && imports.doc.tags.some(function (t) {
      return t.title === 'deprecated' && (moduleDeprecation = t);
    })) {
      context.report({ node: node, message: message(moduleDeprecation) });
    }

    if (imports.errors.length) {
      imports.reportErrors(context, node);
      return;
    }

    node.specifiers.forEach(function (im) {
      var imported = void 0,
          local = void 0;
      switch (im.type) {

        case 'ImportNamespaceSpecifier':
          {
            if (!imports.size) return;
            namespaces.set(im.local.name, imports);
            return;
          }

        case 'ImportDefaultSpecifier':
          imported = 'default';
          local = im.local.name;
          break;

        case 'ImportSpecifier':
          imported = im.imported.name;
          local = im.local.name;
          break;

        default:
          return; // can't handle this one
      }

      // unknown thing can't be deprecated
      var exported = imports.get(imported);
      if (exported == null) return;

      // capture import of deep namespace
      if (exported.namespace) namespaces.set(local, exported.namespace);

      var deprecation = getDeprecation(imports.get(imported));
      if (!deprecation) return;

      context.report({ node: im, message: message(deprecation) });

      deprecated.set(local, deprecation);
    });
  }

  return {
    'Program': function Program(_ref) {
      var body = _ref.body;
      return body.forEach(checkSpecifiers);
    },

    'Identifier': function Identifier(node) {
      if (node.parent.type === 'MemberExpression' && node.parent.property === node) {
        return; // handled by MemberExpression
      }

      // ignore specifier identifiers
      if (node.parent.type.slice(0, 6) === 'Import') return;

      if (!deprecated.has(node.name)) return;

      if ((0, _declaredScope2.default)(context, node.name) !== 'module') return;
      context.report({
        node: node,
        message: message(deprecated.get(node.name))
      });
    },

    'MemberExpression': function MemberExpression(dereference) {
      if (dereference.object.type !== 'Identifier') return;
      if (!namespaces.has(dereference.object.name)) return;

      if ((0, _declaredScope2.default)(context, dereference.object.name) !== 'module') return;

      // go deep
      var namespace = namespaces.get(dereference.object.name);
      var namepath = [dereference.object.name];
      // while property is namespace and parent is member expression, keep validating
      while (namespace instanceof _getExports2.default && dereference.type === 'MemberExpression') {

        // ignore computed parts for now
        if (dereference.computed) return;

        var metadata = namespace.get(dereference.property.name);

        if (!metadata) break;
        var deprecation = getDeprecation(metadata);

        if (deprecation) {
          context.report({ node: dereference.property, message: message(deprecation) });
        }

        // stash and pop
        namepath.push(dereference.property.name);
        namespace = metadata.namespace;
        dereference = dereference.parent;
      }
    }
  };
};

function message(deprecation) {
  return 'Deprecated' + (deprecation.description ? ': ' + deprecation.description : '.');
}

function getDeprecation(metadata) {
  if (!metadata || !metadata.doc) return;

  var deprecation = void 0;
  if (metadata.doc.tags.some(function (t) {
    return t.title === 'deprecated' && (deprecation = t);
  })) {
    return deprecation;
  }
}
//# sourceMappingURL=data:application/json;base64,[encoded data, 10412 characters]