"use strict";

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

var _jsdoctypeparser = require("jsdoctypeparser");

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

var _warnRemovedSettings = _interopRequireDefault(require("../warnRemovedSettings"));

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

const asExpression = /as\s+/u;

var _default = (0, _iterateJsdoc.default)(({
  jsdoc,
  report,
  utils,
  context
}) => {
  (0, _warnRemovedSettings.default)(context, 'valid-types');

  const _ref = context.options[0] || {},
        _ref$allowEmptyNamepa = _ref.allowEmptyNamepaths,
        allowEmptyNamepaths = _ref$allowEmptyNamepa === void 0 ? true : _ref$allowEmptyNamepa,
        _ref$checkSeesForName = _ref.checkSeesForNamepaths,
        checkSeesForNamepaths = _ref$checkSeesForName === void 0 ? false : _ref$checkSeesForName;

  if (!jsdoc.tags) {
    return;
  }

  jsdoc.tags.forEach(tag => {
    const validNamepathParsing = function validNamepathParsing(namepath, tagName) {
      try {
        (0, _jsdoctypeparser.parse)(namepath);
      } catch (error) {
        let handled = false;

        if (tagName) {
          if (['memberof', 'memberof!'].includes(tagName)) {
            const endChar = namepath.slice(-1);

            if (['#', '.', '~'].includes(endChar)) {
              try {
                (0, _jsdoctypeparser.parse)(namepath.slice(0, -1));
                handled = true;
              } catch (memberofError) {// Use the original error for including the whole type
              }
            }
          } else if (tagName === 'borrows') {
            const startChar = namepath.charAt();

            if (['#', '.', '~'].includes(startChar)) {
              try {
                (0, _jsdoctypeparser.parse)(namepath.slice(1));
                handled = true;
              } catch (memberofError) {// Use the original error for including the whole type
              }
            }
          }
        }

        if (!handled) {
          report(`Syntax error in namepath: ${namepath}`, null, tag);
          return false;
        }
      }

      return true;
    };

    const validTypeParsing = function validTypeParsing(type) {
      try {
        (0, _jsdoctypeparser.parse)(type);
      } catch (error) {
        report(`Syntax error in type: ${type}`, null, tag);
        return false;
      }

      return true;
    };

    const hasTypePosition = utils.tagMightHaveTypePosition(tag.tag) && Boolean(tag.type);
    const mustHaveTypePosition = utils.tagMustHaveTypePosition(tag.tag);
    const hasNameOrNamepathPosition = utils.tagMightHaveNamePosition(tag.tag) && Boolean(tag.name) && !(tag.tag === 'see' && !checkSeesForNamepaths);
    const mustHaveNameOrNamepathPosition = utils.tagMustHaveNamePosition(tag.tag) && !allowEmptyNamepaths;
    const hasEither = utils.tagMightHaveEitherTypeOrNamePosition(tag.tag) && hasTypePosition || hasNameOrNamepathPosition;
    const mustHaveEither = utils.tagMustHaveEitherTypeOrNamePosition(tag.tag);

    if (tag.tag === 'borrows') {
      const thisNamepath = tag.description.replace(asExpression, '');

      if (!asExpression.test(tag.description) || !thisNamepath) {
        report(`@borrows must have an "as" expression. Found "${tag.description}"`, null, tag);
        return;
      }

      if (validNamepathParsing(thisNamepath, 'borrows')) {
        const thatNamepath = tag.name;
        validNamepathParsing(thatNamepath);
      }
    } else {
      if (mustHaveEither && !hasEither && !mustHaveTypePosition) {
        report(`Tag @${tag.tag} must have either a type or namepath`, null, tag);
        return;
      }

      if (hasTypePosition) {
        validTypeParsing(tag.type);
      } else if (mustHaveTypePosition) {
        report(`Tag @${tag.tag} must have a type`, null, tag);
      }

      if (hasNameOrNamepathPosition) {
        validNamepathParsing(tag.name, tag.tag);
      } else if (mustHaveNameOrNamepathPosition) {
        report(`Tag @${tag.tag} must have a name/namepath`, null, tag);
      }
    }
  });
}, {
  iterateAllJsdocs: true,
  meta: {
    schema: [{
      additionalProperies: false,
      properties: {
        allowEmptyNamepaths: {
          default: true,
          type: 'boolean'
        },
        checkSeesForNamepaths: {
          default: false,
          type: 'boolean'
        }
      },
      type: 'object'
    }],
    type: 'suggestion'
  }
});

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