UNPKG

eslint-plugin-jsdoc

Version:
362 lines (358 loc) 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc.cjs")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /** * @param {import('@es-joy/jsdoccomment').JsdocBlockWithInline} jsdoc * @param {import('../iterateJsdoc.js').Utils} utils * @param {number} requireSingleLineUnderCount */ const checkForShortTags = (jsdoc, utils, requireSingleLineUnderCount) => { if (!requireSingleLineUnderCount || !jsdoc.tags.length) { return false; } let lastLineWithTag = 0; let isUnderCountLimit = false; let hasMultiDescOrType = false; const tagLines = jsdoc.source.reduce((acc, { tokens: { delimiter, description: desc, name, postDelimiter, postName, postTag, postType, start, tag, type } }, idx) => { if (tag.length) { lastLineWithTag = idx; if (start.length + delimiter.length + postDelimiter.length + type.length + postType.length + name.length + postName.length + tag.length + postTag.length + desc.length < requireSingleLineUnderCount) { isUnderCountLimit = true; } return acc + 1; } else if (desc.length || type.length) { hasMultiDescOrType = true; return acc; } return acc; }, 0); // Could be tagLines > 1 if (!hasMultiDescOrType && isUnderCountLimit && tagLines === 1) { const fixer = () => { const tokens = jsdoc.source[lastLineWithTag].tokens; jsdoc.source = [{ number: 0, source: '', tokens: utils.seedTokens({ delimiter: '/**', description: tokens.description.trimEnd() + ' ', end: '*/', name: tokens.name, postDelimiter: ' ', postName: tokens.postName, postTag: tokens.postTag, postType: tokens.postType, start: jsdoc.source[0].tokens.start, tag: tokens.tag, type: tokens.type }) }]; }; utils.reportJSDoc('Description is too short to be multi-line.', null, fixer); return true; } return false; }; /** * @param {import('@es-joy/jsdoccomment').JsdocBlockWithInline} jsdoc * @param {import('../iterateJsdoc.js').Utils} utils * @param {number} requireSingleLineUnderCount */ const checkForShortDescriptions = (jsdoc, utils, requireSingleLineUnderCount) => { if (!requireSingleLineUnderCount || jsdoc.tags.length) { return false; } let lastLineWithDesc = 0; let isUnderCountLimit = false; const descLines = jsdoc.source.reduce((acc, { tokens: { delimiter, description: desc, postDelimiter, start } }, idx) => { if (desc.length) { lastLineWithDesc = idx; if (start.length + delimiter.length + postDelimiter.length + desc.length < requireSingleLineUnderCount) { isUnderCountLimit = true; } return acc + 1; } return acc; }, 0); // Could be descLines > 1 if (isUnderCountLimit && descLines === 1) { const fixer = () => { const desc = jsdoc.source[lastLineWithDesc].tokens.description; jsdoc.source = [{ number: 0, source: '', tokens: utils.seedTokens({ delimiter: '/**', description: desc.trimEnd() + ' ', end: '*/', postDelimiter: ' ', start: jsdoc.source[0].tokens.start }) }]; }; utils.reportJSDoc('Description is too short to be multi-line.', null, fixer); return true; } return false; }; var _default = exports.default = (0, _iterateJsdoc.default)(({ context, jsdoc, utils }) => { const { allowMultipleTags = true, minimumLengthForMultiline = Number.POSITIVE_INFINITY, multilineTags = ['*'], noFinalLineText = true, noMultilineBlocks = false, noSingleLineBlocks = false, noZeroLineText = true, requireSingleLineUnderCount = null, singleLineTags = ['lends', 'type'] } = context.options[0] || {}; const { source: [{ tokens }] } = jsdoc; const { description, tag } = tokens; const sourceLength = jsdoc.source.length; /** * @param {string} tagName * @returns {boolean} */ 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; } if (checkForShortDescriptions(jsdoc, utils, requireSingleLineUnderCount)) { return; } if (checkForShortTags(jsdoc, utils, requireSingleLineUnderCount)) { 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; for (const prop of ['delimiter', 'postDelimiter', 'tag', 'type', 'lineEnd', 'postType', 'postTag', 'name', 'postName', 'description']) { finalLineTokens[( /** * @type {"delimiter"|"postDelimiter"|"tag"|"type"| * "lineEnd"|"postType"|"postTag"|"name"| * "postName"|"description"} */ 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, lineEnd, name: nme, postName, postTag, postType, tag: tg, type: typ } }) => { 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/blob/main/docs/rules/multiline-blocks.md#repos-sticky-header' }, fixable: 'code', schema: [{ additionalProperties: 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' }, requireSingleLineUnderCount: { type: 'number' }, singleLineTags: { items: { type: 'string' }, type: 'array' } }, type: 'object' }], type: 'suggestion' } }); module.exports = exports.default; //# sourceMappingURL=multilineBlocks.cjs.map