"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _lodash = _interopRequireDefault(require("lodash"));

var _jsdoctypeparser = require("jsdoctypeparser");

var _iterateJsdoc = _interopRequireWildcard(require("../iterateJsdoc"));

var _jsdocUtils = _interopRequireDefault(require("../jsdocUtils"));

function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

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

const extraTypes = ['null', 'undefined', 'void', 'string', 'boolean', 'object', 'function', 'symbol', 'number', 'bigint', 'NaN', 'Infinity', 'any', '*', 'Array', 'Object', 'RegExp', 'Date', 'Function'];

const stripPseudoTypes = str => {
  return str && str.replace(/(?:\.|<>|\.<>|\[\])$/u, '');
};

var _default = (0, _iterateJsdoc.default)(({
  context,
  report,
  settings,
  sourceCode: {
    scopeManager
  },
  utils
}) => {
  const globalScope = scopeManager.globalScope;

  const _ref = context.options[0] || {},
        _ref$definedTypes = _ref.definedTypes,
        definedTypes = _ref$definedTypes === void 0 ? [] : _ref$definedTypes;

  let definedPreferredTypes = [];
  const preferredTypes = settings.preferredTypes;

  if (Object.keys(preferredTypes).length) {
    // Replace `_.values` with `Object.values` when we may start requiring Node 7+
    definedPreferredTypes = _lodash.default.values(preferredTypes).map(preferredType => {
      if (typeof preferredType === 'string') {
        // May become an empty string but will be filtered out below
        return stripPseudoTypes(preferredType);
      }

      if (!preferredType) {
        return undefined;
      }

      if (typeof preferredType !== 'object') {
        utils.reportSettings('Invalid `settings.jsdoc.preferredTypes`. Values must be falsy, a string, or an object.');
      }

      return stripPseudoTypes(preferredType.replacement);
    }).filter(preferredType => {
      return preferredType;
    });
  }

  const typedefDeclarations = (0, _lodash.default)(context.getAllComments()).filter(comment => {
    return comment.value.startsWith('*');
  }).map(_iterateJsdoc.parseComment).flatMap(doc => {
    return (doc.tags || []).filter(({
      tag
    }) => {
      return utils.isNamepathDefiningTag(tag);
    });
  }).map(tag => {
    return tag.name;
  }).value();
  let templateTags = utils.getPresentTags('template');
  const classJsdoc = utils.getClassJsdoc();

  if (classJsdoc && classJsdoc.tags) {
    templateTags = templateTags.concat(classJsdoc.tags.filter(tag => {
      return tag.tag === 'template';
    }));
  }

  const closureGenericTypes = _lodash.default.flatMap(templateTags, tag => {
    return _jsdocUtils.default.parseClosureTemplateTag(tag);
  });

  const allDefinedTypes = globalScope.variables.map(variable => {
    return variable.name;
  }) // If the file is a module, concat the variables from the module scope.
  .concat( // This covers `commonjs` as well as `node`
  scopeManager.__options.nodejsScope || scopeManager.isModule() ? globalScope.childScopes.reduce((arr, {
    variables
  }) => {
    // Flatten
    arr.push(...variables);
    return arr;
  }, []).map(({
    name
  }) => {
    return name;
  }) : []).concat(extraTypes).concat(typedefDeclarations).concat(definedTypes).concat(definedPreferredTypes).concat(settings.mode === 'jsdoc' ? [] : closureGenericTypes);
  const jsdocTagsWithPossibleType = utils.filterTags(tag => {
    return utils.tagMightHaveTypePosition(tag.tag);
  });
  jsdocTagsWithPossibleType.forEach(tag => {
    let parsedType;

    try {
      parsedType = (0, _jsdoctypeparser.parse)(tag.type);
    } catch (error) {
      // On syntax error, will be handled by valid-types.
      return;
    }

    (0, _jsdoctypeparser.traverse)(parsedType, ({
      type,
      name
    }) => {
      if (type === 'NAME') {
        if (!allDefinedTypes.includes(name)) {
          report(`The type '${name}' is undefined.`, null, tag);
        } else if (!_lodash.default.includes(extraTypes, name)) {
          context.markVariableAsUsed(name);
        }
      }
    });
  });
}, {
  iterateAllJsdocs: true,
  meta: {
    schema: [{
      additionalProperties: false,
      properties: {
        definedTypes: {
          items: {
            type: 'string'
          },
          type: 'array'
        }
      },
      type: 'object'
    }],
    type: 'suggestion'
  }
});

exports.default = _default;
module.exports = exports.default;
//# sourceMappingURL=noUndefinedTypes.js.map