"use strict";

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

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

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

var _default = (0, _iterateJsdoc.default)(({
  context,
  jsdoc,
  utils
}) => {
  const {
    allowMultipleTags = true,
    noFinalLineText = true,
    noZeroLineText = true,
    noSingleLineBlocks = false,
    singleLineTags = ['lends', 'type'],
    noMultilineBlocks = false,
    minimumLengthForMultiline = Number.POSITIVE_INFINITY,
    multilineTags = ['*']
  } = context.options[0] || {};
  const {
    source: [{
      tokens
    }]
  } = jsdoc;
  const {
    description,
    tag
  } = tokens;
  const sourceLength = jsdoc.source.length;

  const isInvalidSingleLine = tagName => {
    return noSingleLineBlocks && (!tagName || !singleLineTags.includes(tagName) && !singleLineTags.includes('*'));
  };

  if (sourceLength === 1) {
    if (!isInvalidSingleLine(tag.slice(1))) {
      return;
    }

    const fixer = () => {
      utils.makeMultiline();
    };

    utils.reportJSDoc('Single line blocks are not permitted by your configuration.', null, fixer, true);
    return;
  }

  const lineChecks = () => {
    if (noZeroLineText && (tag || description)) {
      const fixer = () => {
        const line = { ...tokens
        };
        utils.emptyTokens(tokens);
        const {
          tokens: {
            delimiter,
            start
          }
        } = jsdoc.source[1];
        utils.addLine(1, { ...line,
          delimiter,
          start
        });
      };

      utils.reportJSDoc('Should have no text on the "0th" line (after the `/**`).', null, fixer);
      return;
    }

    const finalLine = jsdoc.source[jsdoc.source.length - 1];
    const finalLineTokens = finalLine.tokens;

    if (noFinalLineText && finalLineTokens.description.trim()) {
      const fixer = () => {
        const line = { ...finalLineTokens
        };
        line.description = line.description.trimEnd();
        const {
          delimiter
        } = line;
        ['delimiter', 'postDelimiter', 'tag', 'type', 'lineEnd', 'postType', 'postTag', 'name', 'postName', 'description'].forEach(prop => {
          finalLineTokens[prop] = '';
        });
        utils.addLine(jsdoc.source.length - 1, { ...line,
          delimiter,
          end: ''
        });
      };

      utils.reportJSDoc('Should have no text on the final line (before the `*/`).', null, fixer);
    }
  };

  if (noMultilineBlocks) {
    if (jsdoc.tags.length && (multilineTags.includes('*') || utils.hasATag(multilineTags))) {
      lineChecks();
      return;
    }

    if (jsdoc.description.length >= minimumLengthForMultiline) {
      lineChecks();
      return;
    }

    if (noSingleLineBlocks && (!jsdoc.tags.length || !utils.filterTags(({
      tag: tg
    }) => {
      return !isInvalidSingleLine(tg);
    }).length)) {
      utils.reportJSDoc('Multiline jsdoc blocks are prohibited by ' + 'your configuration but fixing would result in a single ' + 'line block which you have prohibited with `noSingleLineBlocks`.');
      return;
    }

    if (jsdoc.tags.length > 1) {
      if (!allowMultipleTags) {
        utils.reportJSDoc('Multiline jsdoc blocks are prohibited by ' + 'your configuration but the block has multiple tags.');
        return;
      }
    } else if (jsdoc.tags.length === 1 && jsdoc.description.trim()) {
      if (!allowMultipleTags) {
        utils.reportJSDoc('Multiline jsdoc blocks are prohibited by ' + 'your configuration but the block has a description with a tag.');
        return;
      }
    } else {
      const fixer = () => {
        jsdoc.source = [{
          number: 1,
          source: '',
          tokens: jsdoc.source.reduce((obj, {
            tokens: {
              description: desc,
              tag: tg,
              type: typ,
              name: nme,
              lineEnd,
              postType,
              postName,
              postTag
            }
          }) => {
            if (typ) {
              obj.type = typ;
            }

            if (tg && typ && nme) {
              obj.postType = postType;
            }

            if (nme) {
              obj.name += nme;
            }

            if (nme && desc) {
              obj.postName = postName;
            }

            obj.description += desc;
            const nameOrDescription = obj.description || obj.name;

            if (nameOrDescription && nameOrDescription.slice(-1) !== ' ') {
              obj.description += ' ';
            }

            obj.lineEnd = lineEnd; // Already filtered for multiple tags

            obj.tag += tg;

            if (tg) {
              obj.postTag = postTag || ' ';
            }

            return obj;
          }, utils.seedTokens({
            delimiter: '/**',
            end: '*/',
            postDelimiter: ' '
          }))
        }];
      };

      utils.reportJSDoc('Multiline jsdoc blocks are prohibited by ' + 'your configuration.', null, fixer);
      return;
    }
  }

  lineChecks();
}, {
  iterateAllJsdocs: true,
  meta: {
    docs: {
      description: 'Controls how and whether jsdoc blocks can be expressed as single or multiple line blocks.',
      url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-multiline-blocks'
    },
    fixable: 'code',
    schema: [{
      additionalProperies: false,
      properties: {
        allowMultipleTags: {
          type: 'boolean'
        },
        minimumLengthForMultiline: {
          type: 'integer'
        },
        multilineTags: {
          anyOf: [{
            enum: ['*'],
            type: 'string'
          }, {
            items: {
              type: 'string'
            },
            type: 'array'
          }]
        },
        noFinalLineText: {
          type: 'boolean'
        },
        noMultilineBlocks: {
          type: 'boolean'
        },
        noSingleLineBlocks: {
          type: 'boolean'
        },
        noZeroLineText: {
          type: 'boolean'
        },
        singleLineTags: {
          items: {
            type: 'string'
          },
          type: 'array'
        }
      },
      type: 'object'
    }],
    type: 'suggestion'
  }
});

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