Skip to content

Commit 19fa3dc

Browse files
LukeAbbybrettz9
andauthored
fix(lines-before-block): Only trigger after ';', '}', '|', and '&' (#1383)
* fix(lines-before-block): Only trigger after ';', '}', '|', and '&'; fixes #1379 and #1343 * fix(lines-before-block): Switch lintedPunctuators to a Set --------- Co-authored-by: Brett Zamir <[email protected]>
1 parent f32989c commit 19fa3dc

File tree

3 files changed

+234
-2
lines changed

3 files changed

+234
-2
lines changed

docs/rules/lines-before-block.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,27 @@ const values = [
130130
];
131131
// "jsdoc/lines-before-block": ["error"|"warn", {"checkBlockStarts":true}]
132132
// Message: Required 1 line(s) before JSDoc block
133+
134+
type UnionDocumentation =
135+
/** Description. */
136+
| { someProp: number }
137+
/** Description. */
138+
| { otherProp: string }
139+
140+
type IntersectionDocumentation =
141+
/** Description. */
142+
{ someProp: number } &
143+
/** Description. */
144+
{ otherProp: string }
145+
// Message: Required 1 line(s) before JSDoc block
146+
147+
type IntersectionDocumentation = {
148+
someProp: number;
149+
} & /** Description. */ {
150+
otherProp: string;
151+
};
152+
// "jsdoc/lines-before-block": ["error"|"warn", {"ignoreSameLine":false}]
153+
// Message: Required 1 line(s) before JSDoc block
133154
````
134155

135156

@@ -210,5 +231,54 @@ function myFunction() {
210231
*/
211232
let value;
212233
}
234+
235+
class SomeClass {
236+
constructor(
237+
/**
238+
* Description.
239+
*/
240+
param
241+
) {};
242+
243+
method(
244+
/**
245+
* Description.
246+
*/
247+
param
248+
) {};
249+
}
250+
251+
type FunctionAlias1 =
252+
/**
253+
* @param param - Description.
254+
*/
255+
(param: number) => void;
256+
257+
type FunctionAlias2 = (
258+
/**
259+
* @param param - Description.
260+
*/
261+
param: number
262+
) => void;
263+
264+
type UnionDocumentation =
265+
/** Description. */
266+
| { someProp: number }
267+
268+
/** Description. */
269+
| { otherProp: string }
270+
271+
type IntersectionDocumentation =
272+
/** Description. */
273+
{ someProp: number } &
274+
275+
/** Description. */
276+
{ otherProp: string }
277+
278+
type IntersectionDocumentation = {
279+
someProp: number;
280+
} & /** Description. */ {
281+
otherProp: string;
282+
};
213283
````
214284

src/rules/linesBeforeBlock.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import iterateJsdoc from '../iterateJsdoc.js';
22

3+
/**
4+
* `;` ends a previous statement, `}` ends a previous block, `|` is seen the middle of a union, and
5+
* `&` is seen in the middle of an intersection. All other punctuators are for things like arrays,
6+
* functions, type aliases, and so on that shouldn't require a line before it.
7+
*/
8+
const lintedPunctuators = new Set([';', '}', '|', '&']);
9+
310
export default iterateJsdoc(({
411
context,
512
jsdocNode,
@@ -19,8 +26,14 @@ export default iterateJsdoc(({
1926
}
2027

2128
const tokensBefore = sourceCode.getTokensBefore(jsdocNode, {includeComments: true});
22-
const tokenBefore = tokensBefore.slice(-1)[0];
23-
if (!tokenBefore || (tokenBefore.value === '{' && !checkBlockStarts)) {
29+
const tokenBefore = tokensBefore.at(-1);
30+
if (
31+
!tokenBefore || (
32+
tokenBefore.type === 'Punctuator' &&
33+
!checkBlockStarts &&
34+
!lintedPunctuators.has(tokenBefore.value)
35+
)
36+
) {
2437
return;
2538
}
2639

test/rules/assertions/linesBeforeBlock.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {parser as typescriptEslintParser} from 'typescript-eslint';
2+
13
export default /** @type {import('../index.js').TestCases} */ ({
24
invalid: [
35
{
@@ -264,6 +266,83 @@ export default /** @type {import('../index.js').TestCases} */ ({
264266
value,
265267
];
266268
`,
269+
},
270+
{
271+
code: `
272+
type UnionDocumentation =
273+
/** Description. */
274+
| { someProp: number }
275+
/** Description. */
276+
| { otherProp: string }
277+
278+
type IntersectionDocumentation =
279+
/** Description. */
280+
{ someProp: number } &
281+
/** Description. */
282+
{ otherProp: string }
283+
`,
284+
errors: [
285+
{
286+
line: 5,
287+
message: 'Required 1 line(s) before JSDoc block'
288+
},
289+
{
290+
line: 11,
291+
message: 'Required 1 line(s) before JSDoc block'
292+
}
293+
],
294+
languageOptions: {
295+
parser: typescriptEslintParser
296+
},
297+
output: `
298+
type UnionDocumentation =
299+
/** Description. */
300+
| { someProp: number }
301+
302+
/** Description. */
303+
| { otherProp: string }
304+
305+
type IntersectionDocumentation =
306+
/** Description. */
307+
{ someProp: number } &
308+
309+
/** Description. */
310+
{ otherProp: string }
311+
`,
312+
},
313+
{
314+
// While this looks ugly this is exactly how Prettier currently requires such an intersection
315+
// to be formatted. See https://github.com/prettier/prettier/issues/3986.
316+
code: `
317+
type IntersectionDocumentation = {
318+
someProp: number;
319+
} & /** Description. */ {
320+
otherProp: string;
321+
};
322+
`,
323+
errors: [
324+
{
325+
line: 4,
326+
message: 'Required 1 line(s) before JSDoc block'
327+
},
328+
],
329+
languageOptions: {
330+
parser: typescriptEslintParser
331+
},
332+
options: [
333+
{
334+
ignoreSameLine: false,
335+
}
336+
],
337+
output: `
338+
type IntersectionDocumentation = {
339+
someProp: number;
340+
} &
341+
342+
/** Description. */ {
343+
otherProp: string;
344+
};
345+
`
267346
}
268347
],
269348
valid: [
@@ -375,6 +454,76 @@ export default /** @type {import('../index.js').TestCases} */ ({
375454
let value;
376455
}
377456
`,
457+
},
458+
{
459+
code: `
460+
class SomeClass {
461+
constructor(
462+
/**
463+
* Description.
464+
*/
465+
param
466+
) {};
467+
468+
method(
469+
/**
470+
* Description.
471+
*/
472+
param
473+
) {};
474+
}
475+
`,
476+
},
477+
{
478+
code: `
479+
type FunctionAlias1 =
480+
/**
481+
* @param param - Description.
482+
*/
483+
(param: number) => void;
484+
485+
type FunctionAlias2 = (
486+
/**
487+
* @param param - Description.
488+
*/
489+
param: number
490+
) => void;
491+
`,
492+
languageOptions: {
493+
parser: typescriptEslintParser
494+
},
495+
},
496+
{
497+
code: `
498+
type UnionDocumentation =
499+
/** Description. */
500+
| { someProp: number }
501+
502+
/** Description. */
503+
| { otherProp: string }
504+
505+
type IntersectionDocumentation =
506+
/** Description. */
507+
{ someProp: number } &
508+
509+
/** Description. */
510+
{ otherProp: string }
511+
`,
512+
languageOptions: {
513+
parser: typescriptEslintParser
514+
},
515+
},
516+
{
517+
code: `
518+
type IntersectionDocumentation = {
519+
someProp: number;
520+
} & /** Description. */ {
521+
otherProp: string;
522+
};
523+
`,
524+
languageOptions: {
525+
parser: typescriptEslintParser
526+
},
378527
}
379528
],
380529
});

0 commit comments

Comments
 (0)