"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc.cjs"));
var _areDocsInformative = require("are-docs-informative");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const defaultAliases = {
  a: ['an', 'our']
};
const defaultUselessWords = ['a', 'an', 'i', 'in', 'of', 's', 'the'];

/**
 * @param {import('eslint').Rule.Node|import('@typescript-eslint/types').TSESTree.Node|null|undefined} node
 * @returns {string[]}
 */
const getNamesFromNode = node => {
  switch (node?.type) {
    case 'AccessorProperty':
    case 'MethodDefinition':
    case 'PropertyDefinition':
    case 'TSAbstractAccessorProperty':
    case 'TSAbstractMethodDefinition':
    case 'TSAbstractPropertyDefinition':
      return [...getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.Node} */node.parent.parent), ...getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.Node} */
      node.key)];
    case 'ClassDeclaration':
    case 'ClassExpression':
    case 'FunctionDeclaration':
    case 'FunctionExpression':
    case 'TSDeclareFunction':
    case 'TSEnumDeclaration':
    case 'TSEnumMember':
    case 'TSInterfaceDeclaration':
    case 'TSMethodSignature':
    case 'TSModuleDeclaration':
    case 'TSTypeAliasDeclaration':
      return getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.ClassDeclaration} */
      node.id);
    case 'ExportDefaultDeclaration':
    case 'ExportNamedDeclaration':
      return getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.ExportNamedDeclaration} */
      node.declaration);
    case 'Identifier':
      return [node.name];
    case 'Property':
      return getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.Node} */
      node.key);
    case 'VariableDeclaration':
      return getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.Node} */
      node.declarations[0]);
    case 'VariableDeclarator':
      return [...getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.Node} */
      node.id), ...getNamesFromNode(/** @type {import('@typescript-eslint/types').TSESTree.Node} */
      node.init)].filter(Boolean);
    default:
      return [];
  }
};
var _default = exports.default = (0, _iterateJsdoc.default)(({
  context,
  jsdoc,
  node,
  report,
  utils
}) => {
  const /** @type {{aliases: {[key: string]: string[]}, excludedTags: string[], uselessWords: string[]}} */{
    aliases = defaultAliases,
    excludedTags = [],
    uselessWords = defaultUselessWords
  } = context.options[0] || {};
  const nodeNames = getNamesFromNode(node);

  /**
   * @param {string} text
   * @param {string} extraName
   * @returns {boolean}
   */
  const descriptionIsRedundant = (text, extraName = '') => {
    const textTrimmed = text.trim();
    return Boolean(textTrimmed) && !(0, _areDocsInformative.areDocsInformative)(textTrimmed, [extraName, nodeNames].filter(Boolean).join(' '), {
      aliases,
      uselessWords
    });
  };
  const {
    description,
    lastDescriptionLine
  } = utils.getDescription();
  let descriptionReported = false;
  for (const tag of jsdoc.tags) {
    if (excludedTags.includes(tag.tag)) {
      continue;
    }
    if (descriptionIsRedundant(tag.description, tag.name)) {
      utils.reportJSDoc('This tag description only repeats the name it describes.', tag);
    }
    descriptionReported ||= tag.description === description && /** @type {import('comment-parser').Spec & {line: import('../iterateJsdoc.js').Integer}} */
    tag.line === lastDescriptionLine;
  }
  if (!descriptionReported && descriptionIsRedundant(description)) {
    report('This description only repeats the name it describes.');
  }
}, {
  iterateAllJsdocs: true,
  meta: {
    docs: {
      description: 'This rule reports doc comments that only restate their attached name.',
      url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/informative-docs.md#repos-sticky-header'
    },
    schema: [{
      additionalProperties: false,
      properties: {
        aliases: {
          description: `The \`aliases\` option allows indicating words as synonyms (aliases) of each other.

For example, with \`{ aliases: { emoji: ["smiley", "winkey"] } }\`, the following comment would be considered uninformative:

\`\`\`js
/** A smiley/winkey. */
let emoji;
\`\`\`

The default \`aliases\` option is:

\`\`\`json
{
  "a": ["an", "our"]
}
\`\`\``,
          patternProperties: {
            '.*': {
              items: {
                type: 'string'
              },
              type: 'array'
            }
          }
        },
        excludedTags: {
          description: `Tags that should not be checked for valid contents.

For example, with \`{ excludedTags: ["category"] }\`, the following comment would not be considered uninformative:

\`\`\`js
/** @category Types */
function computeTypes(node) {
  // ...
}
\`\`\`

No tags are excluded by default.`,
          items: {
            type: 'string'
          },
          type: 'array'
        },
        uselessWords: {
          description: `Words that are ignored when searching for one that adds meaning.

For example, with \`{ uselessWords: ["our"] }\`, the following comment would be considered uninformative:

\`\`\`js
/** Our text. */
let text;
\`\`\`

The default \`uselessWords\` option is:

\`\`\`json
["a", "an", "i", "in", "of", "s", "the"]
\`\`\``,
          items: {
            type: 'string'
          },
          type: 'array'
        }
      },
      type: 'object'
    }],
    type: 'suggestion'
  }
});
module.exports = exports.default;
//# sourceMappingURL=informativeDocs.cjs.map