Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ non-default-recommended fixer).
|:heavy_check_mark:|:wrench:|[empty-tags](./docs/rules/empty-tags.md#readme)|Checks tags that are expected to be empty (e.g., `@abstract` or `@async`), reporting if they have content|
|:heavy_check_mark:||[implements-on-classes](./docs/rules/implements-on-classes.md#readme)|Prohibits use of `@implements` on non-constructor functions (to enforce the tag only being used on classes/constructors)|
|||[informative-docs](./docs/rules/informative-docs.md#readme)|Reports on JSDoc texts that serve only to restate their attached name.|
|:heavy_check_mark:||[lines-before-block](./docs/rules/lines-before-block.md#readme)|Enforces minimum number of newlines before JSDoc comment blocks|
|||[match-description](./docs/rules/match-description.md#readme)|Defines customizable regular expression rules for your tag descriptions|
||:wrench:|[match-name](./docs/rules/match-name.md#readme)|Reports the name portion of a JSDoc tag if matching or not matching a given regular expression|
|:heavy_check_mark:|:wrench:|[multiline-blocks](./docs/rules/multiline-blocks.md#readme)|Controls how and whether jsdoc blocks can be expressed as single or multiple line blocks|
Expand Down
37 changes: 37 additions & 0 deletions .README/rules/lines-before-block.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# `lines-before-block`

This rule enforces minimum number of newlines before JSDoc comment blocks
(except at the beginning of a file).

## Options

### `lines`

The minimum number of lines to require. Defaults to 1.

### `ignoreSameLine`

This option excludes cases where the JSDoc block occurs on the same line as a
preceding code or comment. Defaults to `true`.

### `excludedTags`

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).

|||
|---|---|
|Context|everywhere|
|Tags|N/A|
|Recommended|true|
|Settings||
|Options|`excludedTags`, `ignoreSameLine`, `lines`|

## Failing examples

<!-- assertions-failing linesBeforeBlock -->

## Passing examples

<!-- assertions-passing linesBeforeBlock -->
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ non-default-recommended fixer).
|:heavy_check_mark:|:wrench:|[empty-tags](./docs/rules/empty-tags.md#readme)|Checks tags that are expected to be empty (e.g., `@abstract` or `@async`), reporting if they have content|
|:heavy_check_mark:||[implements-on-classes](./docs/rules/implements-on-classes.md#readme)|Prohibits use of `@implements` on non-constructor functions (to enforce the tag only being used on classes/constructors)|
|||[informative-docs](./docs/rules/informative-docs.md#readme)|Reports on JSDoc texts that serve only to restate their attached name.|
|:heavy_check_mark:||[lines-before-block](./docs/rules/lines-before-block.md#readme)|Enforces minimum number of newlines before JSDoc comment blocks|
|||[match-description](./docs/rules/match-description.md#readme)|Defines customizable regular expression rules for your tag descriptions|
||:wrench:|[match-name](./docs/rules/match-name.md#readme)|Reports the name portion of a JSDoc tag if matching or not matching a given regular expression|
|:heavy_check_mark:|:wrench:|[multiline-blocks](./docs/rules/multiline-blocks.md#readme)|Controls how and whether jsdoc blocks can be expressed as single or multiple line blocks|
Expand Down
150 changes: 150 additions & 0 deletions docs/rules/lines-before-block.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<a name="user-content-lines-before-block"></a>
<a name="lines-before-block"></a>
# <code>lines-before-block</code>

This rule enforces minimum number of newlines before JSDoc comment blocks
(except at the beginning of a file).

<a name="user-content-lines-before-block-options"></a>
<a name="lines-before-block-options"></a>
## Options

<a name="user-content-lines-before-block-options-lines"></a>
<a name="lines-before-block-options-lines"></a>
### <code>lines</code>

The minimum number of lines to require. Defaults to 1.

<a name="user-content-lines-before-block-options-ignoresameline"></a>
<a name="lines-before-block-options-ignoresameline"></a>
### <code>ignoreSameLine</code>

This option excludes cases where the JSDoc block occurs on the same line as a
preceding code or comment. Defaults to `true`.

<a name="user-content-lines-before-block-options-excludedtags"></a>
<a name="lines-before-block-options-excludedtags"></a>
### <code>excludedTags</code>

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).

|||
|---|---|
|Context|everywhere|
|Tags|N/A|
|Recommended|true|
|Settings||
|Options|`excludedTags`, `ignoreSameLine`, `lines`|

<a name="user-content-lines-before-block-failing-examples"></a>
<a name="lines-before-block-failing-examples"></a>
## Failing examples

The following patterns are considered problems:

````ts
someCode;
/**
*
*/
// Message: Required 1 line(s) before JSDoc block

someCode; /**
*
*/
// "jsdoc/lines-before-block": ["error"|"warn", {"ignoreSameLine":false}]
// Message: Required 1 line(s) before JSDoc block

someCode; /** */
// "jsdoc/lines-before-block": ["error"|"warn", {"ignoreSameLine":false}]
// Message: Required 1 line(s) before JSDoc block

someCode;
/**
*
*/
// "jsdoc/lines-before-block": ["error"|"warn", {"lines":2}]
// Message: Required 2 line(s) before JSDoc block

// Some comment
/**
*
*/
// Message: Required 1 line(s) before JSDoc block

/* Some comment */
/**
*
*/
// Message: Required 1 line(s) before JSDoc block

/**
* Some comment
*/
/**
*
*/
// Message: Required 1 line(s) before JSDoc block
````



<a name="user-content-lines-before-block-passing-examples"></a>
<a name="lines-before-block-passing-examples"></a>
## Passing examples

The following patterns are not considered problems:

````ts
/**
*
*/

someCode;

/**
*
*/

someCode;


/**
*
*/
// "jsdoc/lines-before-block": ["error"|"warn", {"lines":2}]

// Some comment

/**
*
*/

/* Some comment */

/**
*
*/

/**
* Some comment
*/

/**
*
*/

someCode; /** */

const a = {
someProp: /** @type {SomeCast} */ (someVal)
};

const a = /** @lends SomeClass */ {
someProp: (someVal)
};
// "jsdoc/lines-before-block": ["error"|"warn", {"excludedTags":["lends"],"ignoreSameLine":false}]
````

3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import emptyTags from './rules/emptyTags.js';
import implementsOnClasses from './rules/implementsOnClasses.js';
import importsAsDependencies from './rules/importsAsDependencies.js';
import informativeDocs from './rules/informativeDocs.js';
import linesBeforeBlock from './rules/linesBeforeBlock.js';
import matchDescription from './rules/matchDescription.js';
import matchName from './rules/matchName.js';
import multilineBlocks from './rules/multilineBlocks.js';
Expand Down Expand Up @@ -92,6 +93,7 @@ const index = {
'implements-on-classes': implementsOnClasses,
'imports-as-dependencies': importsAsDependencies,
'informative-docs': informativeDocs,
'lines-before-block': linesBeforeBlock,
'match-description': matchDescription,
'match-name': matchName,
'multiline-blocks': multilineBlocks,
Expand Down Expand Up @@ -167,6 +169,7 @@ const createRecommendedRuleset = (warnOrError, flatName) => {
'jsdoc/implements-on-classes': warnOrError,
'jsdoc/imports-as-dependencies': 'off',
'jsdoc/informative-docs': 'off',
'jsdoc/lines-before-block': warnOrError,
'jsdoc/match-description': 'off',
'jsdoc/match-name': 'off',
'jsdoc/multiline-blocks': warnOrError,
Expand Down
101 changes: 101 additions & 0 deletions src/rules/linesBeforeBlock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import iterateJsdoc from '../iterateJsdoc.js';

export default iterateJsdoc(({
context,
jsdocNode,
sourceCode,
report,
utils,
}) => {
const {
lines = 1,
ignoreSameLine = true,
excludedTags = ['type']
} = context.options[0] || {};

if (utils.hasATag(excludedTags)) {
return;
}

const tokensBefore = sourceCode.getTokensBefore(jsdocNode, {includeComments: true});
const tokenBefore = tokensBefore.slice(-1)[0];
if (!tokenBefore) {
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;
}

/** @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]*) \*/)?.[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: {
fixable: 'code',
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',
},
schema: [
{
additionalProperties: false,
properties: {
excludedTags: {
type: 'array',
items: {
type: 'string'
}
},
ignoreSameLine: {
type: 'boolean',
},
lines: {
type: 'integer'
}
},
type: 'object',
},
],
type: 'suggestion',
},
});
Loading