| import iterateJsdoc from '../iterateJsdoc.js'; |
| import { |
| parse as commentParser, |
| } from 'comment-parser'; |
| |
| // Neither a single nor 3+ asterisks are valid JSDoc per |
| // https://jsdoc.app/about-getting-started.html#adding-documentation-comments-to-your-code |
| const commentRegexp = /^\/\*(?!\*)/v; |
| const extraAsteriskCommentRegexp = /^\/\*{3,}/v; |
| |
| export default iterateJsdoc(({ |
| allComments, |
| context, |
| makeReport, |
| sourceCode, |
| }) => { |
| const [ |
| { |
| ignore = [ |
| 'ts-check', |
| 'ts-expect-error', |
| 'ts-ignore', |
| 'ts-nocheck', |
| ], |
| preventAllMultiAsteriskBlocks = false, |
| } = {}, |
| ] = context.options; |
| |
| let extraAsterisks = false; |
| const nonJsdocNodes = /** @type {import('estree').Node[]} */ ( |
| allComments |
| ).filter((comment) => { |
| const commentText = sourceCode.getText(comment); |
| |
| const initialText = commentText.replace(commentRegexp, '').trimStart(); |
| if ([ |
| 'eslint', |
| ].some((directive) => { |
| return initialText.startsWith(directive); |
| })) { |
| return false; |
| } |
| |
| let sliceIndex = 2; |
| if (!commentRegexp.test(commentText)) { |
| const multiline = extraAsteriskCommentRegexp.exec(commentText)?.[0]; |
| if (!multiline) { |
| return false; |
| } |
| |
| sliceIndex = multiline.length; |
| extraAsterisks = true; |
| if (preventAllMultiAsteriskBlocks) { |
| return true; |
| } |
| } |
| |
| const tags = (commentParser( |
| `${commentText.slice(0, 2)}*${commentText.slice(sliceIndex)}`, |
| )[0] || {}).tags ?? []; |
| |
| return tags.length && !tags.some(({ |
| tag, |
| }) => { |
| return ignore.includes(tag); |
| }); |
| }); |
| |
| if (!nonJsdocNodes.length) { |
| return; |
| } |
| |
| for (const node of nonJsdocNodes) { |
| const report = /** @type {import('../iterateJsdoc.js').MakeReport} */ ( |
| makeReport |
| )(context, node); |
| |
| // eslint-disable-next-line no-loop-func |
| const fix = /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => { |
| const text = sourceCode.getText(node); |
| |
| return fixer.replaceText( |
| node, |
| extraAsterisks ? |
| text.replace(extraAsteriskCommentRegexp, '/**') : |
| text.replace('/*', '/**'), |
| ); |
| }; |
| |
| report('Expected JSDoc-like comment to begin with two asterisks.', fix); |
| } |
| }, { |
| checkFile: true, |
| meta: { |
| docs: { |
| description: 'This rule checks for multi-line-style comments which fail to meet the criteria of a JSDoc block.', |
| url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-bad-blocks.md#repos-sticky-header', |
| }, |
| fixable: 'code', |
| schema: [ |
| { |
| additionalProperties: false, |
| properties: { |
| ignore: { |
| description: `An array of directives that will not be reported if present at the beginning of |
| a multi-comment block and at-sign \`/* @\`. |
| |
| Defaults to \`['ts-check', 'ts-expect-error', 'ts-ignore', 'ts-nocheck']\` |
| (some directives [used by TypeScript](https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html#ts-check)).`, |
| items: { |
| type: 'string', |
| }, |
| type: 'array', |
| }, |
| preventAllMultiAsteriskBlocks: { |
| description: `A boolean (defaulting to \`false\`) which if \`true\` will prevent all |
| JSDoc-like blocks with more than two initial asterisks even those without |
| apparent tag content.`, |
| type: 'boolean', |
| }, |
| }, |
| type: 'object', |
| }, |
| ], |
| type: 'layout', |
| }, |
| }); |