@@ -3,58 +3,21 @@ import type { Comment, Expression, Node } from 'estree'
33import { createRule } from '../utils/createRule.js'
44import { isTestExpression , unwrapExpression } from '../utils/test-expression.js'
55
6- /**
7- * An ESLint rule that ensures consistent spacing between test blocks (e.g.
8- * `test`, `test.step`, `test.beforeEach`, etc.). This rule helps improve the
9- * readability and maintainability of test code by ensuring that test blocks are
10- * clearly separated from each other.
11- */
126export default createRule ( {
137 create ( context ) {
14- /**
15- * Recursively determines the previous token (if present) and, if necessary,
16- * a stand-in token to check spacing against. Therefore, the current start
17- * token can optionally be passed through and used as the comparison token.
18- *
19- * Returns the previous token that is not a comment or a grouping expression
20- * (`previous`), the first token to compare (`start`), and the actual token
21- * being examined (`origin`).
22- *
23- * If there is no previous token for the expression, `null` is returned for
24- * it. Ideally, the first comparable token is the same as the actual token.
25- *
26- * | 1 | test('foo', async () => {
27- * previous > | 2 | await test.step(...);
28- * | 3 |
29- * start > | 4 | // Erster Kommentar
30- * | 5 | // weiterer Kommentar
31- * origin > | 6 | await test.step(...);
32- */
338 function getPreviousToken (
349 node : AST . Token | Node ,
3510 start ?: AST . Token | Comment | Node ,
3611 ) : {
37- /** The token actually being checked */
3812 origin : AST . Token | Node
39-
40- /**
41- * The previous token that is neither a comment nor a grouping expression,
42- * if present
43- */
4413 previous : AST . Token | null
45-
46- /**
47- * The first token used for comparison, e.g. the start of the test
48- * expression
49- */
5014 start : AST . Token | Comment | Node
5115 } {
5216 const current = start ?? node
5317 const previous = context . sourceCode . getTokenBefore ( current , {
5418 includeComments : true ,
5519 } )
5620
57- // no predecessor present
5821 if (
5922 previous === null ||
6023 previous === undefined ||
@@ -67,47 +30,29 @@ export default createRule({
6730 }
6831 }
6932
70- // Recursively traverse comments and determine a stand-in
71- // and unwrap parenthesized expressions
7233 if (
73- previous . type === 'Line' || // line comment
74- previous . type === 'Block' || // block comment
75- previous . value === '(' // grouping operator
34+ previous . type === 'Line' ||
35+ previous . type === 'Block' ||
36+ previous . value === '('
7637 ) {
7738 return getPreviousToken ( node , previous )
7839 }
7940
80- // Return result
8141 return {
8242 origin : node ,
8343 previous : previous as AST . Token ,
8444 start : current ,
8545 }
8646 }
8747
88- /**
89- * Checks whether the spacing before the given test block meets
90- * expectations. Optionally an offset token can be provided to check
91- * against, for example in the case of an assignment.
92- *
93- * @param node - The node to be checked.
94- * @param offset - Optional offset token to check spacing against.
95- */
9648 function checkSpacing ( node : Expression , offset ?: AST . Token | Node ) {
9749 const { previous, start } = getPreviousToken ( node , offset )
98-
99- // First expression or no previous token
10050 if ( previous === null ) return
101-
102- // Ignore when there is one or more blank lines between
10351 if ( previous . loc . end . line < start . loc ! . start . line - 1 ) {
10452 return
10553 }
10654
107- // Since the hint in the IDE may not appear on the affected test expression
108- // but possibly on the preceding comment, include the test expression in the message
10955 const source = context . sourceCode . getText ( unwrapExpression ( node ) )
110-
11156 context . report ( {
11257 data : { source } ,
11358 fix ( fixer ) {
@@ -129,22 +74,14 @@ export default createRule({
12974 }
13075
13176 return {
132- // Checks call expressions that could be test steps,
133- // e.g. `test(...)`, `test.step(...)`, or `await test.step(...)`, but also `foo = test(...)`
13477 ExpressionStatement ( node ) {
13578 if ( isTestExpression ( context , node . expression ) ) {
13679 checkSpacing ( node . expression )
13780 }
13881 } ,
139- // Checks declarations that might be initialized from return values of test steps,
140- // e.g. `let result = await test(...)` or `const result = await test.step(...)`
14182 VariableDeclaration ( node ) {
14283 node . declarations . forEach ( ( declaration ) => {
14384 if ( declaration . init && isTestExpression ( context , declaration . init ) ) {
144- // When declaring a variable, our examined test expression is used for initialization.
145- // Therefore, to check spacing we use the keyword token (let, const, var) before it:
146- // 1 | const foo = test('foo', () => {});
147- // 2 | ^
14885 const offset = context . sourceCode . getTokenBefore ( declaration )
14986 checkSpacing ( declaration . init , offset ?? undefined )
15087 }
0 commit comments