UNPKG

eslint-plugin-jsdoc

Version:
145 lines (133 loc) 4.23 kB
import iterateJsdoc from '../iterateJsdoc.js'; /** * Punctuators that begin a logical group should not require a line before it skipped. Specifically * `[` starts an array, `{` starts an object or block, `(` starts a grouping, and `=` starts a * declaration (like a variable or a type alias). */ const startPunctuators = new Set([ '(', '=', '[', '{', ]); export default iterateJsdoc(({ context, jsdocNode, report, sourceCode, utils, }) => { const { checkBlockStarts, excludedTags = [ 'type', ], ignoreSameLine = true, ignoreSingleLines = true, lines = 1, } = context.options[0] || {}; if (utils.hasATag(excludedTags)) { return; } const tokensBefore = sourceCode.getTokensBefore(jsdocNode, { includeComments: true, }); const tokenBefore = tokensBefore.at(-1); if ( !tokenBefore || ( tokenBefore.type === 'Punctuator' && !checkBlockStarts && startPunctuators.has(tokenBefore.value) ) ) { return; } if (tokenBefore.loc?.end?.line + lines >= /** @type {number} */ (jsdocNode.loc?.start?.line) ) { const startLine = jsdocNode.loc?.start?.line; const sameLine = tokenBefore.loc?.end?.line === startLine; if (sameLine && ignoreSameLine) { return; } if (ignoreSingleLines && jsdocNode.loc?.start.line === jsdocNode.loc?.end.line) { return; } /** @type {import('eslint').Rule.ReportFixer} */ const fix = (fixer) => { let indent = ''; if (sameLine) { const spaceDiff = /** @type {number} */ (jsdocNode.loc?.start?.column) - /** @type {number} */ (tokenBefore.loc?.end?.column); // @ts-expect-error Should be a comment indent = /** @type {import('estree').Comment} */ ( jsdocNode ).value.match(/^\*\n([\t ]*) \*/v)?.[1]?.slice(spaceDiff); if (!indent) { /** @type {import('eslint').AST.Token|import('estree').Comment|undefined} */ let tokenPrior = tokenBefore; let startColumn; while (tokenPrior && tokenPrior?.loc?.start?.line === startLine) { startColumn = tokenPrior.loc?.start?.column; tokenPrior = tokensBefore.pop(); } indent = ' '.repeat( /* c8 ignore next */ /** @type {number} */ (startColumn ? startColumn - 1 : 0), ); } } return fixer.insertTextAfter( /** @type {import('eslint').AST.Token} */ (tokenBefore), '\n'.repeat(lines) + (sameLine ? '\n' + indent : ''), ); }; report(`Required ${lines} line(s) before JSDoc block`, fix); } }, { iterateAllJsdocs: true, meta: { docs: { description: 'Enforces minimum number of newlines before JSDoc comment blocks', url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/lines-before-block.md#repos-sticky-header', }, fixable: 'code', schema: [ { additionalProperties: false, properties: { checkBlockStarts: { description: `Whether to additionally check the start of blocks, such as classes or functions. Defaults to \`false\`.`, type: 'boolean', }, excludedTags: { description: `An array of tags whose presence in the JSDoc block will prevent the application of the rule. Defaults to \`['type']\` (i.e., if \`@type\` is present, lines before the block will not be added).`, items: { type: 'string', }, type: 'array', }, ignoreSameLine: { description: `This option excludes cases where the JSDoc block occurs on the same line as a preceding code or comment. Defaults to \`true\`.`, type: 'boolean', }, ignoreSingleLines: { description: `This option excludes cases where the JSDoc block is only one line long. Defaults to \`true\`.`, type: 'boolean', }, lines: { description: 'The minimum number of lines to require. Defaults to 1.', type: 'integer', }, }, type: 'object', }, ], type: 'suggestion', }, });