eslint-plugin-jsdoc 62.5.5 → 62.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,6 +66,7 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
66
66
  endLines = 0,
67
67
  maxBlockLines = null,
68
68
  startLines = 0,
69
+ startLinesWithNoTags = null,
69
70
  tags = {}
70
71
  } = {}] = context.options;
71
72
  jsdoc.tags.some((tg, tagIdx) => {
@@ -209,8 +210,9 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
209
210
  })) {
210
211
  return;
211
212
  }
212
- if (typeof startLines === 'number') {
213
- if (!jsdoc.tags.length) {
213
+ if (typeof startLines === 'number' || typeof startLinesWithNoTags === 'number') {
214
+ const noTags = !jsdoc.tags.length;
215
+ if (noTags && startLinesWithNoTags === null) {
214
216
  return;
215
217
  }
216
218
  const {
@@ -220,10 +222,11 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
220
222
  if (!/\S/v.test(description)) {
221
223
  return;
222
224
  }
225
+ const startingLines = noTags ? startLinesWithNoTags : startLines;
223
226
  const trailingLines = description.match(/\n+$/v)?.[0]?.length;
224
- const trailingDiff = (trailingLines ?? 0) - startLines;
227
+ const trailingDiff = (trailingLines ?? 0) - startingLines;
225
228
  if (trailingDiff > 0) {
226
- utils.reportJSDoc(`Expected only ${startLines} line${startLines === 1 ? '' : 's'} after block description`, {
229
+ utils.reportJSDoc(`Expected only ${startingLines} line${startingLines === 1 ? '' : 's'} after block description`, {
227
230
  line: lastDescriptionLine - trailingDiff
228
231
  }, () => {
229
232
  utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {
@@ -241,7 +244,7 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
241
244
  });
242
245
  });
243
246
  } else if (trailingDiff < 0) {
244
- utils.reportJSDoc(`Expected ${startLines} lines after block description`, {
247
+ utils.reportJSDoc(`Expected ${startingLines} lines after block description`, {
245
248
  line: lastDescriptionLine
246
249
  }, () => {
247
250
  utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {
@@ -274,7 +277,7 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
274
277
  fixable: 'code',
275
278
  schema: [{
276
279
  description: `Defaults to "never". "any" is only useful with \`tags\` (allowing non-enforcement of lines except
277
- for particular tags) or with \`startLines\`, \`endLines\`, or \`maxBlockLines\`. It is also
280
+ for particular tags) or with \`startLines\`, \`startLinesWithNoTags\` \`endLines\`, or \`maxBlockLines\`. It is also
278
281
  necessary if using the linebreak-setting options of the \`sort-tags\` rule
279
282
  so that the two rules won't conflict in both attempting to set lines
280
283
  between tags.`,
@@ -331,6 +334,10 @@ a line count will not be enforced.
331
334
 
332
335
  Defaults to \`0\`.`
333
336
  },
337
+ startLinesWithNoTags: {
338
+ description: 'If set to a number, will enforce a starting lines count when there are no tags. Defaults to `undefined`.',
339
+ type: 'number'
340
+ },
334
341
  tags: {
335
342
  description: `Overrides the default behavior depending on specific tags.
336
343
 
@@ -1 +1 @@
1
- {"version":3,"file":"tagLines.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","e","__esModule","default","checkMaxBlockLines","maxBlockLines","startLines","utils","reportJSDoc","description","getDescription","excessBlockLinesRegex","RegExp","excessBlockLinesMatch","match","excessBlockLines","length","excessIndexLine","slice","index","line","setBlockDescription","info","seedTokens","descLines","postDelims","newPostDelims","map","desc","idx","number","source","tokens","postDelimiter","_default","exports","iterateJsdoc","context","jsdoc","alwaysNever","applyToEndTag","count","endLines","tags","options","some","tg","tagIdx","lastTag","lastEmpty","reportIndex","emptyLinesCount","end","name","tag","type","entries","includes","lines","empty","lineDiff","fixer","removeTag","tagSourceOffset","addLines","currentTag","tagSourceIdx","splice","push","currentTg","tagCount","defaultAlways","overrideAlways","fixCount","lastDescriptionLine","test","trailingLines","trailingDiff","Array","from","trim","iterateAllJsdocs","meta","docs","url","fixable","schema","enum","additionalProperties","properties","anyOf","patternProperties","module"],"sources":["../../src/rules/tagLines.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\n\n/**\n * @param {{\n * maxBlockLines: null|number,\n * startLines: null|number,\n * utils: import('../iterateJsdoc.js').Utils\n * }} cfg\n */\nconst checkMaxBlockLines = ({\n maxBlockLines,\n startLines,\n utils,\n}) => {\n if (typeof maxBlockLines !== 'number') {\n return false;\n }\n\n if (typeof startLines === 'number' && maxBlockLines < startLines) {\n utils.reportJSDoc(\n 'If set to a number, `maxBlockLines` must be greater than or equal to `startLines`.',\n );\n return true;\n }\n\n const {\n description,\n } = utils.getDescription();\n const excessBlockLinesRegex = new RegExp('\\n{' + (maxBlockLines + 2) + ',}', 'v');\n const excessBlockLinesMatch = description.match(excessBlockLinesRegex);\n const excessBlockLines = excessBlockLinesMatch?.[0]?.length ?? 0;\n if (excessBlockLinesMatch) {\n const excessIndexLine = description.slice(0, excessBlockLinesMatch.index).match(/\\n/gv)?.length ?? 0;\n utils.reportJSDoc(\n `Expected a maximum of ${maxBlockLines} line${maxBlockLines === 1 ? '' : 's'} within block description`,\n {\n line: excessIndexLine,\n },\n () => {\n utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {\n const newPostDelims = [\n ...postDelims.slice(0, excessIndexLine),\n ...postDelims.slice(excessIndexLine + excessBlockLines - 1 - maxBlockLines),\n ];\n return [\n ...descLines.slice(0, excessIndexLine),\n ...descLines.slice(excessIndexLine + excessBlockLines - 1 - maxBlockLines),\n ].map((desc, idx) => {\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: desc,\n postDelimiter: newPostDelims[idx],\n }),\n };\n });\n });\n },\n );\n return true;\n }\n\n return false;\n};\n\nexport default iterateJsdoc(({\n context,\n jsdoc,\n utils,\n}) => {\n const [\n alwaysNever = 'never',\n {\n applyToEndTag = true,\n count = 1,\n endLines = 0,\n maxBlockLines = null,\n startLines = 0,\n tags = {},\n } = {},\n ] = context.options;\n\n jsdoc.tags.some((tg, tagIdx) => {\n let lastTag;\n\n /**\n * @type {null|import('../iterateJsdoc.js').Integer}\n */\n let lastEmpty = null;\n\n /**\n * @type {null|import('../iterateJsdoc.js').Integer}\n */\n let reportIndex = null;\n let emptyLinesCount = 0;\n for (const [\n idx,\n {\n tokens: {\n description,\n end,\n name,\n tag,\n type,\n },\n },\n ] of tg.source.entries()) {\n // May be text after a line break within a tag description\n if (description) {\n reportIndex = null;\n }\n\n if (lastTag && [\n 'always', 'any',\n ].includes(tags[lastTag.slice(1)]?.lines)) {\n continue;\n }\n\n const empty = !tag && !name && !type && !description;\n if (\n empty && !end &&\n (alwaysNever === 'never' ||\n lastTag && tags[lastTag.slice(1)]?.lines === 'never'\n )\n ) {\n reportIndex = idx;\n\n continue;\n }\n\n if (!end) {\n if (empty) {\n emptyLinesCount++;\n } else {\n emptyLinesCount = 0;\n }\n\n lastEmpty = empty ? idx : null;\n }\n\n lastTag = tag;\n }\n\n if (\n typeof endLines === 'number' &&\n lastEmpty !== null && tagIdx === jsdoc.tags.length - 1\n ) {\n const lineDiff = endLines - emptyLinesCount;\n\n if (lineDiff < 0) {\n const fixer = () => {\n utils.removeTag(tagIdx, {\n tagSourceOffset: /** @type {import('../iterateJsdoc.js').Integer} */ (\n lastEmpty\n ) + lineDiff + 1,\n });\n };\n\n utils.reportJSDoc(\n `Expected ${endLines} trailing lines`,\n {\n line: tg.source[lastEmpty].number + lineDiff + 1,\n },\n fixer,\n );\n } else if (lineDiff > 0) {\n const fixer = () => {\n utils.addLines(\n tagIdx,\n /** @type {import('../iterateJsdoc.js').Integer} */ (lastEmpty),\n endLines - emptyLinesCount,\n );\n };\n\n utils.reportJSDoc(\n `Expected ${endLines} trailing lines`,\n {\n line: tg.source[lastEmpty].number,\n },\n fixer,\n );\n }\n\n return true;\n }\n\n if (reportIndex !== null) {\n const fixer = () => {\n utils.removeTag(tagIdx, {\n tagSourceOffset: /** @type {import('../iterateJsdoc.js').Integer} */ (\n reportIndex\n ),\n });\n };\n\n utils.reportJSDoc(\n 'Expected no lines between tags',\n {\n line: tg.source[0].number + 1,\n },\n fixer,\n );\n\n return true;\n }\n\n return false;\n });\n\n (applyToEndTag ? jsdoc.tags : jsdoc.tags.slice(0, -1)).some((tg, tagIdx) => {\n /**\n * @type {{\n * idx: import('../iterateJsdoc.js').Integer,\n * number: import('../iterateJsdoc.js').Integer\n * }[]}\n */\n const lines = [];\n\n let currentTag;\n let tagSourceIdx = 0;\n for (const [\n idx,\n {\n number,\n tokens: {\n description,\n end,\n name,\n tag,\n type,\n },\n },\n ] of tg.source.entries()) {\n if (description) {\n lines.splice(0);\n tagSourceIdx = idx;\n }\n\n if (tag) {\n currentTag = tag;\n }\n\n if (!tag && !name && !type && !description && !end) {\n lines.push({\n idx,\n number,\n });\n }\n }\n\n const currentTg = currentTag && tags[currentTag.slice(1)];\n const tagCount = currentTg?.count;\n\n const defaultAlways = alwaysNever === 'always' && currentTg?.lines !== 'never' &&\n currentTg?.lines !== 'any' && lines.length < count;\n\n let overrideAlways;\n let fixCount = count;\n if (!defaultAlways) {\n fixCount = typeof tagCount === 'number' ? tagCount : count;\n overrideAlways = currentTg?.lines === 'always' &&\n lines.length < fixCount;\n }\n\n if (defaultAlways || overrideAlways) {\n const fixer = () => {\n utils.addLines(tagIdx, lines[lines.length - 1]?.idx || tagSourceIdx + 1, fixCount - lines.length);\n };\n\n const line = lines[lines.length - 1]?.number || tg.source[tagSourceIdx].number;\n utils.reportJSDoc(\n `Expected ${fixCount} line${fixCount === 1 ? '' : 's'} between tags but found ${lines.length}`,\n {\n line,\n },\n fixer,\n );\n\n return true;\n }\n\n return false;\n });\n\n if (checkMaxBlockLines({\n maxBlockLines,\n startLines,\n utils,\n })) {\n return;\n }\n\n if (typeof startLines === 'number') {\n if (!jsdoc.tags.length) {\n return;\n }\n\n const {\n description,\n lastDescriptionLine,\n } = utils.getDescription();\n if (!(/\\S/v).test(description)) {\n return;\n }\n\n const trailingLines = description.match(/\\n+$/v)?.[0]?.length;\n const trailingDiff = (trailingLines ?? 0) - startLines;\n if (trailingDiff > 0) {\n utils.reportJSDoc(\n `Expected only ${startLines} line${startLines === 1 ? '' : 's'} after block description`,\n {\n line: lastDescriptionLine - trailingDiff,\n },\n () => {\n utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {\n return descLines.slice(0, -trailingDiff).map((desc, idx) => {\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: desc,\n postDelimiter: postDelims[idx],\n }),\n };\n });\n });\n },\n );\n } else if (trailingDiff < 0) {\n utils.reportJSDoc(\n `Expected ${startLines} lines after block description`,\n {\n line: lastDescriptionLine,\n },\n () => {\n utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {\n return [\n ...descLines,\n ...Array.from({\n length: -trailingDiff,\n }, () => {\n return '';\n }),\n ].map((desc, idx) => {\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: desc,\n postDelimiter: desc.trim() ? postDelims[idx] : '',\n }),\n };\n });\n });\n },\n );\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Enforces lines (or no lines) before, after, or between tags.',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/tag-lines.md#repos-sticky-header',\n },\n fixable: 'code',\n schema: [\n {\n description: `Defaults to \"never\". \"any\" is only useful with \\`tags\\` (allowing non-enforcement of lines except\nfor particular tags) or with \\`startLines\\`, \\`endLines\\`, or \\`maxBlockLines\\`. It is also\nnecessary if using the linebreak-setting options of the \\`sort-tags\\` rule\nso that the two rules won't conflict in both attempting to set lines\nbetween tags.`,\n enum: [\n 'always', 'any', 'never',\n ],\n type: 'string',\n },\n {\n additionalProperties: false,\n properties: {\n applyToEndTag: {\n description: `Set to \\`false\\` and use with \"always\" to indicate the normal lines to be\nadded after tags should not be added after the final tag.\n\nDefaults to \\`true\\`.`,\n type: 'boolean',\n },\n count: {\n description: `Use with \"always\" to indicate the number of lines to require be present.\n\nDefaults to 1.`,\n type: 'integer',\n },\n endLines: {\n anyOf: [\n {\n type: 'integer',\n },\n {\n type: 'null',\n },\n ],\n description: `If not set to \\`null\\`, will enforce end lines to the given count on the\nfinal tag only.\n\nDefaults to \\`0\\`.`,\n },\n maxBlockLines: {\n anyOf: [\n {\n type: 'integer',\n },\n {\n type: 'null',\n },\n ],\n description: `If not set to \\`null\\`, will enforce a maximum number of lines to the given count anywhere in the block description.\n\nNote that if non-\\`null\\`, \\`maxBlockLines\\` must be greater than or equal to \\`startLines\\`.\n\nDefaults to \\`null\\`.`,\n },\n startLines: {\n anyOf: [\n {\n type: 'integer',\n },\n {\n type: 'null',\n },\n ],\n description: `If not set to \\`null\\`, will enforce end lines to the given count before the\nfirst tag only, unless there is only whitespace content, in which case,\na line count will not be enforced.\n\nDefaults to \\`0\\`.`,\n },\n tags: {\n description: `Overrides the default behavior depending on specific tags.\n\nAn object whose keys are tag names and whose values are objects with the\nfollowing keys:\n\n1. \\`lines\\` - Set to \\`always\\`, \\`never\\`, or \\`any\\` to override.\n2. \\`count\\` - Overrides main \\`count\\` (for \"always\")\n\nDefaults to empty object.`,\n patternProperties: {\n '.*': {\n additionalProperties: false,\n properties: {\n count: {\n type: 'integer',\n },\n lines: {\n enum: [\n 'always', 'never', 'any',\n ],\n type: 'string',\n },\n },\n },\n },\n type: 'object',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"tagLines.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","e","__esModule","default","checkMaxBlockLines","maxBlockLines","startLines","utils","reportJSDoc","description","getDescription","excessBlockLinesRegex","RegExp","excessBlockLinesMatch","match","excessBlockLines","length","excessIndexLine","slice","index","line","setBlockDescription","info","seedTokens","descLines","postDelims","newPostDelims","map","desc","idx","number","source","tokens","postDelimiter","_default","exports","iterateJsdoc","context","jsdoc","alwaysNever","applyToEndTag","count","endLines","startLinesWithNoTags","tags","options","some","tg","tagIdx","lastTag","lastEmpty","reportIndex","emptyLinesCount","end","name","tag","type","entries","includes","lines","empty","lineDiff","fixer","removeTag","tagSourceOffset","addLines","currentTag","tagSourceIdx","splice","push","currentTg","tagCount","defaultAlways","overrideAlways","fixCount","noTags","lastDescriptionLine","test","startingLines","trailingLines","trailingDiff","Array","from","trim","iterateAllJsdocs","meta","docs","url","fixable","schema","enum","additionalProperties","properties","anyOf","patternProperties","module"],"sources":["../../src/rules/tagLines.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\n\n/**\n * @param {{\n * maxBlockLines: null|number,\n * startLines: null|number,\n * utils: import('../iterateJsdoc.js').Utils\n * }} cfg\n */\nconst checkMaxBlockLines = ({\n maxBlockLines,\n startLines,\n utils,\n}) => {\n if (typeof maxBlockLines !== 'number') {\n return false;\n }\n\n if (typeof startLines === 'number' && maxBlockLines < startLines) {\n utils.reportJSDoc(\n 'If set to a number, `maxBlockLines` must be greater than or equal to `startLines`.',\n );\n return true;\n }\n\n const {\n description,\n } = utils.getDescription();\n const excessBlockLinesRegex = new RegExp('\\n{' + (maxBlockLines + 2) + ',}', 'v');\n const excessBlockLinesMatch = description.match(excessBlockLinesRegex);\n const excessBlockLines = excessBlockLinesMatch?.[0]?.length ?? 0;\n if (excessBlockLinesMatch) {\n const excessIndexLine = description.slice(0, excessBlockLinesMatch.index).match(/\\n/gv)?.length ?? 0;\n utils.reportJSDoc(\n `Expected a maximum of ${maxBlockLines} line${maxBlockLines === 1 ? '' : 's'} within block description`,\n {\n line: excessIndexLine,\n },\n () => {\n utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {\n const newPostDelims = [\n ...postDelims.slice(0, excessIndexLine),\n ...postDelims.slice(excessIndexLine + excessBlockLines - 1 - maxBlockLines),\n ];\n return [\n ...descLines.slice(0, excessIndexLine),\n ...descLines.slice(excessIndexLine + excessBlockLines - 1 - maxBlockLines),\n ].map((desc, idx) => {\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: desc,\n postDelimiter: newPostDelims[idx],\n }),\n };\n });\n });\n },\n );\n return true;\n }\n\n return false;\n};\n\nexport default iterateJsdoc(({\n context,\n jsdoc,\n utils,\n}) => {\n const [\n alwaysNever = 'never',\n {\n applyToEndTag = true,\n count = 1,\n endLines = 0,\n maxBlockLines = null,\n startLines = 0,\n startLinesWithNoTags = null,\n tags = {},\n } = {},\n ] = context.options;\n\n jsdoc.tags.some((tg, tagIdx) => {\n let lastTag;\n\n /**\n * @type {null|import('../iterateJsdoc.js').Integer}\n */\n let lastEmpty = null;\n\n /**\n * @type {null|import('../iterateJsdoc.js').Integer}\n */\n let reportIndex = null;\n let emptyLinesCount = 0;\n for (const [\n idx,\n {\n tokens: {\n description,\n end,\n name,\n tag,\n type,\n },\n },\n ] of tg.source.entries()) {\n // May be text after a line break within a tag description\n if (description) {\n reportIndex = null;\n }\n\n if (lastTag && [\n 'always', 'any',\n ].includes(tags[lastTag.slice(1)]?.lines)) {\n continue;\n }\n\n const empty = !tag && !name && !type && !description;\n if (\n empty && !end &&\n (alwaysNever === 'never' ||\n lastTag && tags[lastTag.slice(1)]?.lines === 'never'\n )\n ) {\n reportIndex = idx;\n\n continue;\n }\n\n if (!end) {\n if (empty) {\n emptyLinesCount++;\n } else {\n emptyLinesCount = 0;\n }\n\n lastEmpty = empty ? idx : null;\n }\n\n lastTag = tag;\n }\n\n if (\n typeof endLines === 'number' &&\n lastEmpty !== null && tagIdx === jsdoc.tags.length - 1\n ) {\n const lineDiff = endLines - emptyLinesCount;\n\n if (lineDiff < 0) {\n const fixer = () => {\n utils.removeTag(tagIdx, {\n tagSourceOffset: /** @type {import('../iterateJsdoc.js').Integer} */ (\n lastEmpty\n ) + lineDiff + 1,\n });\n };\n\n utils.reportJSDoc(\n `Expected ${endLines} trailing lines`,\n {\n line: tg.source[lastEmpty].number + lineDiff + 1,\n },\n fixer,\n );\n } else if (lineDiff > 0) {\n const fixer = () => {\n utils.addLines(\n tagIdx,\n /** @type {import('../iterateJsdoc.js').Integer} */ (lastEmpty),\n endLines - emptyLinesCount,\n );\n };\n\n utils.reportJSDoc(\n `Expected ${endLines} trailing lines`,\n {\n line: tg.source[lastEmpty].number,\n },\n fixer,\n );\n }\n\n return true;\n }\n\n if (reportIndex !== null) {\n const fixer = () => {\n utils.removeTag(tagIdx, {\n tagSourceOffset: /** @type {import('../iterateJsdoc.js').Integer} */ (\n reportIndex\n ),\n });\n };\n\n utils.reportJSDoc(\n 'Expected no lines between tags',\n {\n line: tg.source[0].number + 1,\n },\n fixer,\n );\n\n return true;\n }\n\n return false;\n });\n\n (applyToEndTag ? jsdoc.tags : jsdoc.tags.slice(0, -1)).some((tg, tagIdx) => {\n /**\n * @type {{\n * idx: import('../iterateJsdoc.js').Integer,\n * number: import('../iterateJsdoc.js').Integer\n * }[]}\n */\n const lines = [];\n\n let currentTag;\n let tagSourceIdx = 0;\n for (const [\n idx,\n {\n number,\n tokens: {\n description,\n end,\n name,\n tag,\n type,\n },\n },\n ] of tg.source.entries()) {\n if (description) {\n lines.splice(0);\n tagSourceIdx = idx;\n }\n\n if (tag) {\n currentTag = tag;\n }\n\n if (!tag && !name && !type && !description && !end) {\n lines.push({\n idx,\n number,\n });\n }\n }\n\n const currentTg = currentTag && tags[currentTag.slice(1)];\n const tagCount = currentTg?.count;\n\n const defaultAlways = alwaysNever === 'always' && currentTg?.lines !== 'never' &&\n currentTg?.lines !== 'any' && lines.length < count;\n\n let overrideAlways;\n let fixCount = count;\n if (!defaultAlways) {\n fixCount = typeof tagCount === 'number' ? tagCount : count;\n overrideAlways = currentTg?.lines === 'always' &&\n lines.length < fixCount;\n }\n\n if (defaultAlways || overrideAlways) {\n const fixer = () => {\n utils.addLines(tagIdx, lines[lines.length - 1]?.idx || tagSourceIdx + 1, fixCount - lines.length);\n };\n\n const line = lines[lines.length - 1]?.number || tg.source[tagSourceIdx].number;\n utils.reportJSDoc(\n `Expected ${fixCount} line${fixCount === 1 ? '' : 's'} between tags but found ${lines.length}`,\n {\n line,\n },\n fixer,\n );\n\n return true;\n }\n\n return false;\n });\n\n if (checkMaxBlockLines({\n maxBlockLines,\n startLines,\n utils,\n })) {\n return;\n }\n\n if (typeof startLines === 'number' || typeof startLinesWithNoTags === 'number') {\n const noTags = !jsdoc.tags.length;\n\n if (noTags && startLinesWithNoTags === null) {\n return;\n }\n\n const {\n description,\n lastDescriptionLine,\n } = utils.getDescription();\n if (!(/\\S/v).test(description)) {\n return;\n }\n\n const startingLines = noTags ? startLinesWithNoTags : startLines;\n\n const trailingLines = description.match(/\\n+$/v)?.[0]?.length;\n const trailingDiff = (trailingLines ?? 0) - startingLines;\n if (trailingDiff > 0) {\n utils.reportJSDoc(\n `Expected only ${startingLines} line${startingLines === 1 ? '' : 's'} after block description`,\n {\n line: lastDescriptionLine - trailingDiff,\n },\n () => {\n utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {\n return descLines.slice(0, -trailingDiff).map((desc, idx) => {\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: desc,\n postDelimiter: postDelims[idx],\n }),\n };\n });\n });\n },\n );\n } else if (trailingDiff < 0) {\n utils.reportJSDoc(\n `Expected ${startingLines} lines after block description`,\n {\n line: lastDescriptionLine,\n },\n () => {\n utils.setBlockDescription((info, seedTokens, descLines, postDelims) => {\n return [\n ...descLines,\n ...Array.from({\n length: -trailingDiff,\n }, () => {\n return '';\n }),\n ].map((desc, idx) => {\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: desc,\n postDelimiter: desc.trim() ? postDelims[idx] : '',\n }),\n };\n });\n });\n },\n );\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Enforces lines (or no lines) before, after, or between tags.',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/tag-lines.md#repos-sticky-header',\n },\n fixable: 'code',\n schema: [\n {\n description: `Defaults to \"never\". \"any\" is only useful with \\`tags\\` (allowing non-enforcement of lines except\nfor particular tags) or with \\`startLines\\`, \\`startLinesWithNoTags\\` \\`endLines\\`, or \\`maxBlockLines\\`. It is also\nnecessary if using the linebreak-setting options of the \\`sort-tags\\` rule\nso that the two rules won't conflict in both attempting to set lines\nbetween tags.`,\n enum: [\n 'always', 'any', 'never',\n ],\n type: 'string',\n },\n {\n additionalProperties: false,\n properties: {\n applyToEndTag: {\n description: `Set to \\`false\\` and use with \"always\" to indicate the normal lines to be\nadded after tags should not be added after the final tag.\n\nDefaults to \\`true\\`.`,\n type: 'boolean',\n },\n count: {\n description: `Use with \"always\" to indicate the number of lines to require be present.\n\nDefaults to 1.`,\n type: 'integer',\n },\n endLines: {\n anyOf: [\n {\n type: 'integer',\n },\n {\n type: 'null',\n },\n ],\n description: `If not set to \\`null\\`, will enforce end lines to the given count on the\nfinal tag only.\n\nDefaults to \\`0\\`.`,\n },\n maxBlockLines: {\n anyOf: [\n {\n type: 'integer',\n },\n {\n type: 'null',\n },\n ],\n description: `If not set to \\`null\\`, will enforce a maximum number of lines to the given count anywhere in the block description.\n\nNote that if non-\\`null\\`, \\`maxBlockLines\\` must be greater than or equal to \\`startLines\\`.\n\nDefaults to \\`null\\`.`,\n },\n startLines: {\n anyOf: [\n {\n type: 'integer',\n },\n {\n type: 'null',\n },\n ],\n description: `If not set to \\`null\\`, will enforce end lines to the given count before the\nfirst tag only, unless there is only whitespace content, in which case,\na line count will not be enforced.\n\nDefaults to \\`0\\`.`,\n },\n startLinesWithNoTags: {\n description: 'If set to a number, will enforce a starting lines count when there are no tags. Defaults to `undefined`.',\n type: 'number',\n },\n tags: {\n description: `Overrides the default behavior depending on specific tags.\n\nAn object whose keys are tag names and whose values are objects with the\nfollowing keys:\n\n1. \\`lines\\` - Set to \\`always\\`, \\`never\\`, or \\`any\\` to override.\n2. \\`count\\` - Overrides main \\`count\\` (for \"always\")\n\nDefaults to empty object.`,\n patternProperties: {\n '.*': {\n additionalProperties: false,\n properties: {\n count: {\n type: 'integer',\n },\n lines: {\n enum: [\n 'always', 'never', 'any',\n ],\n type: 'string',\n },\n },\n },\n },\n type: 'object',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":";;;;;;AAAA,IAAAA,aAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA8C,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAE9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMG,kBAAkB,GAAGA,CAAC;EAC1BC,aAAa;EACbC,UAAU;EACVC;AACF,CAAC,KAAK;EACJ,IAAI,OAAOF,aAAa,KAAK,QAAQ,EAAE;IACrC,OAAO,KAAK;EACd;EAEA,IAAI,OAAOC,UAAU,KAAK,QAAQ,IAAID,aAAa,GAAGC,UAAU,EAAE;IAChEC,KAAK,CAACC,WAAW,CACf,oFACF,CAAC;IACD,OAAO,IAAI;EACb;EAEA,MAAM;IACJC;EACF,CAAC,GAAGF,KAAK,CAACG,cAAc,CAAC,CAAC;EAC1B,MAAMC,qBAAqB,GAAG,IAAIC,MAAM,CAAC,KAAK,IAAIP,aAAa,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC;EACjF,MAAMQ,qBAAqB,GAAGJ,WAAW,CAACK,KAAK,CAACH,qBAAqB,CAAC;EACtE,MAAMI,gBAAgB,GAAGF,qBAAqB,GAAG,CAAC,CAAC,EAAEG,MAAM,IAAI,CAAC;EAChE,IAAIH,qBAAqB,EAAE;IACzB,MAAMI,eAAe,GAAGR,WAAW,CAACS,KAAK,CAAC,CAAC,EAAEL,qBAAqB,CAACM,KAAK,CAAC,CAACL,KAAK,CAAC,MAAM,CAAC,EAAEE,MAAM,IAAI,CAAC;IACpGT,KAAK,CAACC,WAAW,CACf,yBAAyBH,aAAa,QAAQA,aAAa,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,2BAA2B,EACvG;MACEe,IAAI,EAAEH;IACR,CAAC,EACD,MAAM;MACJV,KAAK,CAACc,mBAAmB,CAAC,CAACC,IAAI,EAAEC,UAAU,EAAEC,SAAS,EAAEC,UAAU,KAAK;QACrE,MAAMC,aAAa,GAAG,CACpB,GAAGD,UAAU,CAACP,KAAK,CAAC,CAAC,EAAED,eAAe,CAAC,EACvC,GAAGQ,UAAU,CAACP,KAAK,CAACD,eAAe,GAAGF,gBAAgB,GAAG,CAAC,GAAGV,aAAa,CAAC,CAC5E;QACD,OAAO,CACL,GAAGmB,SAAS,CAACN,KAAK,CAAC,CAAC,EAAED,eAAe,CAAC,EACtC,GAAGO,SAAS,CAACN,KAAK,CAACD,eAAe,GAAGF,gBAAgB,GAAG,CAAC,GAAGV,aAAa,CAAC,CAC3E,CAACsB,GAAG,CAAC,CAACC,IAAI,EAAEC,GAAG,KAAK;UACnB,OAAO;YACLC,MAAM,EAAE,CAAC;YACTC,MAAM,EAAE,EAAE;YACVC,MAAM,EAAET,UAAU,CAAC;cACjB,GAAGD,IAAI;cACPb,WAAW,EAAEmB,IAAI;cACjBK,aAAa,EAAEP,aAAa,CAACG,GAAG;YAClC,CAAC;UACH,CAAC;QACH,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ,CACF,CAAC;IACD,OAAO,IAAI;EACb;EAEA,OAAO,KAAK;AACd,CAAC;AAAC,IAAAK,QAAA,GAAAC,OAAA,CAAAhC,OAAA,GAEa,IAAAiC,qBAAY,EAAC,CAAC;EAC3BC,OAAO;EACPC,KAAK;EACL/B;AACF,CAAC,KAAK;EACJ,MAAM,CACJgC,WAAW,GAAG,OAAO,EACrB;IACEC,aAAa,GAAG,IAAI;IACpBC,KAAK,GAAG,CAAC;IACTC,QAAQ,GAAG,CAAC;IACZrC,aAAa,GAAG,IAAI;IACpBC,UAAU,GAAG,CAAC;IACdqC,oBAAoB,GAAG,IAAI;IAC3BC,IAAI,GAAG,CAAC;EACV,CAAC,GAAG,CAAC,CAAC,CACP,GAAGP,OAAO,CAACQ,OAAO;EAEnBP,KAAK,CAACM,IAAI,CAACE,IAAI,CAAC,CAACC,EAAE,EAAEC,MAAM,KAAK;IAC9B,IAAIC,OAAO;;IAEX;AACJ;AACA;IACI,IAAIC,SAAS,GAAG,IAAI;;IAEpB;AACJ;AACA;IACI,IAAIC,WAAW,GAAG,IAAI;IACtB,IAAIC,eAAe,GAAG,CAAC;IACvB,KAAK,MAAM,CACTvB,GAAG,EACH;MACEG,MAAM,EAAE;QACNvB,WAAW;QACX4C,GAAG;QACHC,IAAI;QACJC,GAAG;QACHC;MACF;IACF,CAAC,CACF,IAAIT,EAAE,CAAChB,MAAM,CAAC0B,OAAO,CAAC,CAAC,EAAE;MACxB;MACA,IAAIhD,WAAW,EAAE;QACf0C,WAAW,GAAG,IAAI;MACpB;MAEA,IAAIF,OAAO,IAAI,CACb,QAAQ,EAAE,KAAK,CAChB,CAACS,QAAQ,CAACd,IAAI,CAACK,OAAO,CAAC/B,KAAK,CAAC,CAAC,CAAC,CAAC,EAAEyC,KAAK,CAAC,EAAE;QACzC;MACF;MAEA,MAAMC,KAAK,GAAG,CAACL,GAAG,IAAI,CAACD,IAAI,IAAI,CAACE,IAAI,IAAI,CAAC/C,WAAW;MACpD,IACEmD,KAAK,IAAI,CAACP,GAAG,KACZd,WAAW,KAAK,OAAO,IACtBU,OAAO,IAAIL,IAAI,CAACK,OAAO,CAAC/B,KAAK,CAAC,CAAC,CAAC,CAAC,EAAEyC,KAAK,KAAK,OAAO,CACrD,EACD;QACAR,WAAW,GAAGtB,GAAG;QAEjB;MACF;MAEA,IAAI,CAACwB,GAAG,EAAE;QACR,IAAIO,KAAK,EAAE;UACTR,eAAe,EAAE;QACnB,CAAC,MAAM;UACLA,eAAe,GAAG,CAAC;QACrB;QAEAF,SAAS,GAAGU,KAAK,GAAG/B,GAAG,GAAG,IAAI;MAChC;MAEAoB,OAAO,GAAGM,GAAG;IACf;IAEA,IACE,OAAOb,QAAQ,KAAK,QAAQ,IAC5BQ,SAAS,KAAK,IAAI,IAAIF,MAAM,KAAKV,KAAK,CAACM,IAAI,CAAC5B,MAAM,GAAG,CAAC,EACtD;MACA,MAAM6C,QAAQ,GAAGnB,QAAQ,GAAGU,eAAe;MAE3C,IAAIS,QAAQ,GAAG,CAAC,EAAE;QAChB,MAAMC,KAAK,GAAGA,CAAA,KAAM;UAClBvD,KAAK,CAACwD,SAAS,CAACf,MAAM,EAAE;YACtBgB,eAAe,EAAE,mDACfd,SAAS,GACPW,QAAQ,GAAG;UACjB,CAAC,CAAC;QACJ,CAAC;QAEDtD,KAAK,CAACC,WAAW,CACf,YAAYkC,QAAQ,iBAAiB,EACrC;UACEtB,IAAI,EAAE2B,EAAE,CAAChB,MAAM,CAACmB,SAAS,CAAC,CAACpB,MAAM,GAAG+B,QAAQ,GAAG;QACjD,CAAC,EACDC,KACF,CAAC;MACH,CAAC,MAAM,IAAID,QAAQ,GAAG,CAAC,EAAE;QACvB,MAAMC,KAAK,GAAGA,CAAA,KAAM;UAClBvD,KAAK,CAAC0D,QAAQ,CACZjB,MAAM,EACN,mDAAqDE,SAAS,EAC9DR,QAAQ,GAAGU,eACb,CAAC;QACH,CAAC;QAED7C,KAAK,CAACC,WAAW,CACf,YAAYkC,QAAQ,iBAAiB,EACrC;UACEtB,IAAI,EAAE2B,EAAE,CAAChB,MAAM,CAACmB,SAAS,CAAC,CAACpB;QAC7B,CAAC,EACDgC,KACF,CAAC;MACH;MAEA,OAAO,IAAI;IACb;IAEA,IAAIX,WAAW,KAAK,IAAI,EAAE;MACxB,MAAMW,KAAK,GAAGA,CAAA,KAAM;QAClBvD,KAAK,CAACwD,SAAS,CAACf,MAAM,EAAE;UACtBgB,eAAe,GAAE;UACfb,WAAW;QAEf,CAAC,CAAC;MACJ,CAAC;MAED5C,KAAK,CAACC,WAAW,CACf,gCAAgC,EAChC;QACEY,IAAI,EAAE2B,EAAE,CAAChB,MAAM,CAAC,CAAC,CAAC,CAACD,MAAM,GAAG;MAC9B,CAAC,EACDgC,KACF,CAAC;MAED,OAAO,IAAI;IACb;IAEA,OAAO,KAAK;EACd,CAAC,CAAC;EAEF,CAACtB,aAAa,GAAGF,KAAK,CAACM,IAAI,GAAGN,KAAK,CAACM,IAAI,CAAC1B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE4B,IAAI,CAAC,CAACC,EAAE,EAAEC,MAAM,KAAK;IAC1E;AACJ;AACA;AACA;AACA;AACA;IACI,MAAMW,KAAK,GAAG,EAAE;IAEhB,IAAIO,UAAU;IACd,IAAIC,YAAY,GAAG,CAAC;IACpB,KAAK,MAAM,CACTtC,GAAG,EACH;MACEC,MAAM;MACNE,MAAM,EAAE;QACNvB,WAAW;QACX4C,GAAG;QACHC,IAAI;QACJC,GAAG;QACHC;MACF;IACF,CAAC,CACF,IAAIT,EAAE,CAAChB,MAAM,CAAC0B,OAAO,CAAC,CAAC,EAAE;MACxB,IAAIhD,WAAW,EAAE;QACfkD,KAAK,CAACS,MAAM,CAAC,CAAC,CAAC;QACfD,YAAY,GAAGtC,GAAG;MACpB;MAEA,IAAI0B,GAAG,EAAE;QACPW,UAAU,GAAGX,GAAG;MAClB;MAEA,IAAI,CAACA,GAAG,IAAI,CAACD,IAAI,IAAI,CAACE,IAAI,IAAI,CAAC/C,WAAW,IAAI,CAAC4C,GAAG,EAAE;QAClDM,KAAK,CAACU,IAAI,CAAC;UACTxC,GAAG;UACHC;QACF,CAAC,CAAC;MACJ;IACF;IAEA,MAAMwC,SAAS,GAAGJ,UAAU,IAAItB,IAAI,CAACsB,UAAU,CAAChD,KAAK,CAAC,CAAC,CAAC,CAAC;IACzD,MAAMqD,QAAQ,GAAGD,SAAS,EAAE7B,KAAK;IAEjC,MAAM+B,aAAa,GAAGjC,WAAW,KAAK,QAAQ,IAAI+B,SAAS,EAAEX,KAAK,KAAK,OAAO,IAC5EW,SAAS,EAAEX,KAAK,KAAK,KAAK,IAAIA,KAAK,CAAC3C,MAAM,GAAGyB,KAAK;IAEpD,IAAIgC,cAAc;IAClB,IAAIC,QAAQ,GAAGjC,KAAK;IACpB,IAAI,CAAC+B,aAAa,EAAE;MAClBE,QAAQ,GAAG,OAAOH,QAAQ,KAAK,QAAQ,GAAGA,QAAQ,GAAG9B,KAAK;MAC1DgC,cAAc,GAAGH,SAAS,EAAEX,KAAK,KAAK,QAAQ,IAC5CA,KAAK,CAAC3C,MAAM,GAAG0D,QAAQ;IAC3B;IAEA,IAAIF,aAAa,IAAIC,cAAc,EAAE;MACnC,MAAMX,KAAK,GAAGA,CAAA,KAAM;QAClBvD,KAAK,CAAC0D,QAAQ,CAACjB,MAAM,EAAEW,KAAK,CAACA,KAAK,CAAC3C,MAAM,GAAG,CAAC,CAAC,EAAEa,GAAG,IAAIsC,YAAY,GAAG,CAAC,EAAEO,QAAQ,GAAGf,KAAK,CAAC3C,MAAM,CAAC;MACnG,CAAC;MAED,MAAMI,IAAI,GAAGuC,KAAK,CAACA,KAAK,CAAC3C,MAAM,GAAG,CAAC,CAAC,EAAEc,MAAM,IAAIiB,EAAE,CAAChB,MAAM,CAACoC,YAAY,CAAC,CAACrC,MAAM;MAC9EvB,KAAK,CAACC,WAAW,CACf,YAAYkE,QAAQ,QAAQA,QAAQ,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,2BAA2Bf,KAAK,CAAC3C,MAAM,EAAE,EAC9F;QACEI;MACF,CAAC,EACD0C,KACF,CAAC;MAED,OAAO,IAAI;IACb;IAEA,OAAO,KAAK;EACd,CAAC,CAAC;EAEF,IAAI1D,kBAAkB,CAAC;IACrBC,aAAa;IACbC,UAAU;IACVC;EACF,CAAC,CAAC,EAAE;IACF;EACF;EAEA,IAAI,OAAOD,UAAU,KAAK,QAAQ,IAAI,OAAOqC,oBAAoB,KAAK,QAAQ,EAAE;IAC9E,MAAMgC,MAAM,GAAG,CAACrC,KAAK,CAACM,IAAI,CAAC5B,MAAM;IAEjC,IAAI2D,MAAM,IAAIhC,oBAAoB,KAAK,IAAI,EAAE;MAC3C;IACF;IAEA,MAAM;MACJlC,WAAW;MACXmE;IACF,CAAC,GAAGrE,KAAK,CAACG,cAAc,CAAC,CAAC;IAC1B,IAAI,CAAE,KAAK,CAAEmE,IAAI,CAACpE,WAAW,CAAC,EAAE;MAC9B;IACF;IAEA,MAAMqE,aAAa,GAAGH,MAAM,GAAGhC,oBAAoB,GAAGrC,UAAU;IAEhE,MAAMyE,aAAa,GAAGtE,WAAW,CAACK,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAEE,MAAM;IAC7D,MAAMgE,YAAY,GAAG,CAACD,aAAa,IAAI,CAAC,IAAID,aAAa;IACzD,IAAIE,YAAY,GAAG,CAAC,EAAE;MACpBzE,KAAK,CAACC,WAAW,CACf,iBAAiBsE,aAAa,QAAQA,aAAa,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,0BAA0B,EAC9F;QACE1D,IAAI,EAAEwD,mBAAmB,GAAGI;MAC9B,CAAC,EACD,MAAM;QACJzE,KAAK,CAACc,mBAAmB,CAAC,CAACC,IAAI,EAAEC,UAAU,EAAEC,SAAS,EAAEC,UAAU,KAAK;UACrE,OAAOD,SAAS,CAACN,KAAK,CAAC,CAAC,EAAE,CAAC8D,YAAY,CAAC,CAACrD,GAAG,CAAC,CAACC,IAAI,EAAEC,GAAG,KAAK;YAC1D,OAAO;cACLC,MAAM,EAAE,CAAC;cACTC,MAAM,EAAE,EAAE;cACVC,MAAM,EAAET,UAAU,CAAC;gBACjB,GAAGD,IAAI;gBACPb,WAAW,EAAEmB,IAAI;gBACjBK,aAAa,EAAER,UAAU,CAACI,GAAG;cAC/B,CAAC;YACH,CAAC;UACH,CAAC,CAAC;QACJ,CAAC,CAAC;MACJ,CACF,CAAC;IACH,CAAC,MAAM,IAAImD,YAAY,GAAG,CAAC,EAAE;MAC3BzE,KAAK,CAACC,WAAW,CACf,YAAYsE,aAAa,gCAAgC,EACzD;QACE1D,IAAI,EAAEwD;MACR,CAAC,EACD,MAAM;QACJrE,KAAK,CAACc,mBAAmB,CAAC,CAACC,IAAI,EAAEC,UAAU,EAAEC,SAAS,EAAEC,UAAU,KAAK;UACrE,OAAO,CACL,GAAGD,SAAS,EACZ,GAAGyD,KAAK,CAACC,IAAI,CAAC;YACZlE,MAAM,EAAE,CAACgE;UACX,CAAC,EAAE,MAAM;YACP,OAAO,EAAE;UACX,CAAC,CAAC,CACH,CAACrD,GAAG,CAAC,CAACC,IAAI,EAAEC,GAAG,KAAK;YACnB,OAAO;cACLC,MAAM,EAAE,CAAC;cACTC,MAAM,EAAE,EAAE;cACVC,MAAM,EAAET,UAAU,CAAC;gBACjB,GAAGD,IAAI;gBACPb,WAAW,EAAEmB,IAAI;gBACjBK,aAAa,EAAEL,IAAI,CAACuD,IAAI,CAAC,CAAC,GAAG1D,UAAU,CAACI,GAAG,CAAC,GAAG;cACjD,CAAC;YACH,CAAC;UACH,CAAC,CAAC;QACJ,CAAC,CAAC;MACJ,CACF,CAAC;IACH;EACF;AACF,CAAC,EAAE;EACDuD,gBAAgB,EAAE,IAAI;EACtBC,IAAI,EAAE;IACJC,IAAI,EAAE;MACJ7E,WAAW,EAAE,8DAA8D;MAC3E8E,GAAG,EAAE;IACP,CAAC;IACDC,OAAO,EAAE,MAAM;IACfC,MAAM,EAAE,CACN;MACEhF,WAAW,EAAE;AACrB;AACA;AACA;AACA,cAAc;MACNiF,IAAI,EAAE,CACJ,QAAQ,EAAE,KAAK,EAAE,OAAO,CACzB;MACDlC,IAAI,EAAE;IACR,CAAC,EACD;MACEmC,oBAAoB,EAAE,KAAK;MAC3BC,UAAU,EAAE;QACVpD,aAAa,EAAE;UACb/B,WAAW,EAAE;AACzB;AACA;AACA,sBAAsB;UACV+C,IAAI,EAAE;QACR,CAAC;QACDf,KAAK,EAAE;UACLhC,WAAW,EAAE;AACzB;AACA,eAAe;UACH+C,IAAI,EAAE;QACR,CAAC;QACDd,QAAQ,EAAE;UACRmD,KAAK,EAAE,CACL;YACErC,IAAI,EAAE;UACR,CAAC,EACD;YACEA,IAAI,EAAE;UACR,CAAC,CACF;UACD/C,WAAW,EAAE;AACzB;AACA;AACA;QACU,CAAC;QACDJ,aAAa,EAAE;UACbwF,KAAK,EAAE,CACL;YACErC,IAAI,EAAE;UACR,CAAC,EACD;YACEA,IAAI,EAAE;UACR,CAAC,CACF;UACD/C,WAAW,EAAE;AACzB;AACA;AACA;AACA;QACU,CAAC;QACDH,UAAU,EAAE;UACVuF,KAAK,EAAE,CACL;YACErC,IAAI,EAAE;UACR,CAAC,EACD;YACEA,IAAI,EAAE;UACR,CAAC,CACF;UACD/C,WAAW,EAAE;AACzB;AACA;AACA;AACA;QACU,CAAC;QACDkC,oBAAoB,EAAE;UACpBlC,WAAW,EAAE,0GAA0G;UACvH+C,IAAI,EAAE;QACR,CAAC;QACDZ,IAAI,EAAE;UACJnC,WAAW,EAAE;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;UACdqF,iBAAiB,EAAE;YACjB,IAAI,EAAE;cACJH,oBAAoB,EAAE,KAAK;cAC3BC,UAAU,EAAE;gBACVnD,KAAK,EAAE;kBACLe,IAAI,EAAE;gBACR,CAAC;gBACDG,KAAK,EAAE;kBACL+B,IAAI,EAAE,CACJ,QAAQ,EAAE,OAAO,EAAE,KAAK,CACzB;kBACDlC,IAAI,EAAE;gBACR;cACF;YACF;UACF,CAAC;UACDA,IAAI,EAAE;QACR;MACF,CAAC;MACDA,IAAI,EAAE;IACR,CAAC,CACF;IACDA,IAAI,EAAE;EACR;AACF,CAAC,CAAC;AAAAuC,MAAA,CAAA5D,OAAA,GAAAA,OAAA,CAAAhC,OAAA","ignoreList":[]}
package/dist/rules.d.ts CHANGED
@@ -2948,6 +2948,10 @@ export interface Rules {
2948
2948
  * Defaults to `0`.
2949
2949
  */
2950
2950
  startLines?: number | null;
2951
+ /**
2952
+ * If set to a number, will enforce a starting lines count when there are no tags. Defaults to `undefined`.
2953
+ */
2954
+ startLinesWithNoTags?: number;
2951
2955
  /**
2952
2956
  * Overrides the default behavior depending on specific tags.
2953
2957
  *
package/package.json CHANGED
@@ -192,5 +192,5 @@
192
192
  "test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
193
193
  "test-index": "pnpm run test-no-cov test/rules/index.js"
194
194
  },
195
- "version": "62.5.5"
195
+ "version": "62.6.0"
196
196
  }
@@ -78,6 +78,7 @@ export default iterateJsdoc(({
78
78
  endLines = 0,
79
79
  maxBlockLines = null,
80
80
  startLines = 0,
81
+ startLinesWithNoTags = null,
81
82
  tags = {},
82
83
  } = {},
83
84
  ] = context.options;
@@ -292,8 +293,10 @@ export default iterateJsdoc(({
292
293
  return;
293
294
  }
294
295
 
295
- if (typeof startLines === 'number') {
296
- if (!jsdoc.tags.length) {
296
+ if (typeof startLines === 'number' || typeof startLinesWithNoTags === 'number') {
297
+ const noTags = !jsdoc.tags.length;
298
+
299
+ if (noTags && startLinesWithNoTags === null) {
297
300
  return;
298
301
  }
299
302
 
@@ -305,11 +308,13 @@ export default iterateJsdoc(({
305
308
  return;
306
309
  }
307
310
 
311
+ const startingLines = noTags ? startLinesWithNoTags : startLines;
312
+
308
313
  const trailingLines = description.match(/\n+$/v)?.[0]?.length;
309
- const trailingDiff = (trailingLines ?? 0) - startLines;
314
+ const trailingDiff = (trailingLines ?? 0) - startingLines;
310
315
  if (trailingDiff > 0) {
311
316
  utils.reportJSDoc(
312
- `Expected only ${startLines} line${startLines === 1 ? '' : 's'} after block description`,
317
+ `Expected only ${startingLines} line${startingLines === 1 ? '' : 's'} after block description`,
313
318
  {
314
319
  line: lastDescriptionLine - trailingDiff,
315
320
  },
@@ -331,7 +336,7 @@ export default iterateJsdoc(({
331
336
  );
332
337
  } else if (trailingDiff < 0) {
333
338
  utils.reportJSDoc(
334
- `Expected ${startLines} lines after block description`,
339
+ `Expected ${startingLines} lines after block description`,
335
340
  {
336
341
  line: lastDescriptionLine,
337
342
  },
@@ -371,7 +376,7 @@ export default iterateJsdoc(({
371
376
  schema: [
372
377
  {
373
378
  description: `Defaults to "never". "any" is only useful with \`tags\` (allowing non-enforcement of lines except
374
- for particular tags) or with \`startLines\`, \`endLines\`, or \`maxBlockLines\`. It is also
379
+ for particular tags) or with \`startLines\`, \`startLinesWithNoTags\` \`endLines\`, or \`maxBlockLines\`. It is also
375
380
  necessary if using the linebreak-setting options of the \`sort-tags\` rule
376
381
  so that the two rules won't conflict in both attempting to set lines
377
382
  between tags.`,
@@ -440,6 +445,10 @@ a line count will not be enforced.
440
445
 
441
446
  Defaults to \`0\`.`,
442
447
  },
448
+ startLinesWithNoTags: {
449
+ description: 'If set to a number, will enforce a starting lines count when there are no tags. Defaults to `undefined`.',
450
+ type: 'number',
451
+ },
443
452
  tags: {
444
453
  description: `Overrides the default behavior depending on specific tags.
445
454
 
package/src/rules.d.ts CHANGED
@@ -2948,6 +2948,10 @@ export interface Rules {
2948
2948
  * Defaults to `0`.
2949
2949
  */
2950
2950
  startLines?: number | null;
2951
+ /**
2952
+ * If set to a number, will enforce a starting lines count when there are no tags. Defaults to `undefined`.
2953
+ */
2954
+ startLinesWithNoTags?: number;
2951
2955
  /**
2952
2956
  * Overrides the default behavior depending on specific tags.
2953
2957
  *