'use strict';var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var _ExportMap = require('../ExportMap');var _ExportMap2 = _interopRequireDefault(_ExportMap);
var _docsUrl = require('../docsUrl');var _docsUrl2 = _interopRequireDefault(_docsUrl);
var _arrayIncludes = require('array-includes');var _arrayIncludes2 = _interopRequireDefault(_arrayIncludes);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };}

/*
                                                                                                                                                                                                          Notes on TypeScript namespaces aka TSModuleDeclaration:
                                                                                                                                                                                                          
                                                                                                                                                                                                          There are two forms:
                                                                                                                                                                                                          - active namespaces: namespace Foo {} / module Foo {}
                                                                                                                                                                                                          - ambient modules; declare module "eslint-plugin-import" {}
                                                                                                                                                                                                          
                                                                                                                                                                                                          active namespaces:
                                                                                                                                                                                                          - cannot contain a default export
                                                                                                                                                                                                          - cannot contain an export all
                                                                                                                                                                                                          - cannot contain a multi name export (export { a, b })
                                                                                                                                                                                                          - can have active namespaces nested within them
                                                                                                                                                                                                          
                                                                                                                                                                                                          ambient namespaces:
                                                                                                                                                                                                          - can only be defined in .d.ts files
                                                                                                                                                                                                          - cannot be nested within active namespaces
                                                                                                                                                                                                          - have no other restrictions
                                                                                                                                                                                                          */

const rootProgram = 'root';
const tsTypePrefix = 'type:';

/**
                               * Detect function overloads like:
                               * ```ts
                               * export function foo(a: number);
                               * export function foo(a: string);
                               * export function foo(a: number|string) { return a; }
                               * ```
                               * @param {Set<Object>} nodes
                               * @returns {boolean}
                               */
function isTypescriptFunctionOverloads(nodes) {
  const types = new Set(Array.from(nodes, node => node.parent.type));
  return (
    types.has('TSDeclareFunction') && (

    types.size === 1 ||
    types.size === 2 && types.has('FunctionDeclaration')));


}

module.exports = {
  meta: {
    type: 'problem',
    docs: {
      url: (0, _docsUrl2.default)('export') },

    schema: [] },


  create: function (context) {
    const namespace = new Map([[rootProgram, new Map()]]);

    function addNamed(name, node, parent, isType) {
      if (!namespace.has(parent)) {
        namespace.set(parent, new Map());
      }
      const named = namespace.get(parent);

      const key = isType ? `${tsTypePrefix}${name}` : name;
      let nodes = named.get(key);

      if (nodes == null) {
        nodes = new Set();
        named.set(key, nodes);
      }

      nodes.add(node);
    }

    function getParent(node) {
      if (node.parent && node.parent.type === 'TSModuleBlock') {
        return node.parent.parent;
      }

      // just in case somehow a non-ts namespace export declaration isn't directly
      // parented to the root Program node
      return rootProgram;
    }

    return {
      'ExportDefaultDeclaration': node => addNamed('default', node, getParent(node)),

      'ExportSpecifier': node => addNamed(node.exported.name, node.exported, getParent(node)),

      'ExportNamedDeclaration': function (node) {
        if (node.declaration == null) return;

        const parent = getParent(node);
        // support for old TypeScript versions
        const isTypeVariableDecl = node.declaration.kind === 'type';

        if (node.declaration.id != null) {
          if ((0, _arrayIncludes2.default)([
          'TSTypeAliasDeclaration',
          'TSInterfaceDeclaration'],
          node.declaration.type)) {
            addNamed(node.declaration.id.name, node.declaration.id, parent, true);
          } else {
            addNamed(node.declaration.id.name, node.declaration.id, parent, isTypeVariableDecl);
          }
        }

        if (node.declaration.declarations != null) {
          for (let declaration of node.declaration.declarations) {
            (0, _ExportMap.recursivePatternCapture)(declaration.id, v =>
            addNamed(v.name, v, parent, isTypeVariableDecl));
          }
        }
      },

      'ExportAllDeclaration': function (node) {
        if (node.source == null) return; // not sure if this is ever true

        // `export * as X from 'path'` does not conflict
        if (node.exported && node.exported.name) return;

        const remoteExports = _ExportMap2.default.get(node.source.value, context);
        if (remoteExports == null) return;

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

        const parent = getParent(node);

        let any = false;
        remoteExports.forEach((v, name) =>
        name !== 'default' && (
        any = true) && // poor man's filter
        addNamed(name, node, parent));

        if (!any) {
          context.report(
          node.source,
          `No named exports found in module '${node.source.value}'.`);

        }
      },

      'Program:exit': function () {
        for (let _ref of namespace) {var _ref2 = _slicedToArray(_ref, 2);let named = _ref2[1];
          for (let _ref3 of named) {var _ref4 = _slicedToArray(_ref3, 2);let name = _ref4[0];let nodes = _ref4[1];
            if (nodes.size <= 1) continue;

            if (isTypescriptFunctionOverloads(nodes)) continue;

            for (let node of nodes) {
              if (name === 'default') {
                context.report(node, 'Multiple default exports.');
              } else {
                context.report(
                node,
                `Multiple exports of name '${name.replace(tsTypePrefix, '')}'.`);

              }
            }
          }
        }
      } };

  } };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 11968 characters]