Skip to content

Commit ea082d5

Browse files
author
barthy
committed
added rule
1 parent 0c0ef9a commit ea082d5

File tree

2 files changed

+112
-98
lines changed

2 files changed

+112
-98
lines changed

lib/rules/empty-line-between-options.js

Lines changed: 38 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
/**
2-
* @author Barthy Bonhomme <[email protected]> <github.com/barthy-koeln>
3-
* @author Sergio Arbeo <[email protected]>
4-
* Adapted from https://github.com/DockYard/eslint-plugin-ember-suave/blob/master/lib/rules/lines-between-object-properties.js
5-
*
2+
* @author Barthy Bonhomme <[email protected]> (https://github.com/barthy-koeln)
63
* See LICENSE file in root directory for full license.
74
*/
85
'use strict'
@@ -11,7 +8,6 @@
118
// Requirements
129
// ------------------------------------------------------------------------------
1310

14-
const path = require('path')
1511
const utils = require('../utils')
1612

1713
// ------------------------------------------------------------------------------
@@ -52,126 +48,74 @@ module.exports = {
5248
const fixFunctions = {
5349
/**
5450
* Removes newlines between component options
51+
*
5552
* @param {RuleFixer} fixer
56-
* @param {Token} currentLast
57-
* @param {Token} nextFirst
53+
* @param {number} endOfCurrent
54+
* @param {number} startOfNext
5855
* @return {Fix}
5956
*/
60-
never(fixer, currentLast, nextFirst) {
61-
return fixer.replaceTextRange(
62-
[currentLast.range[1], nextFirst.range[0]],
63-
',\n'
64-
)
57+
never(fixer, endOfCurrent, startOfNext) {
58+
return fixer.replaceTextRange([endOfCurrent, startOfNext], '\n')
6559
},
6660
/**
67-
* Add newlines between component options
61+
* Add newlines between component options.
62+
*
6863
* @param {RuleFixer} fixer
69-
* @param {Token} currentLast
64+
* @param {number} endOfCurrent
7065
* @return {Fix}
7166
*/
72-
always(fixer, currentLast /*, nextFirst*/) {
73-
const tokenAfterLastToken = sourceCode.getTokenAfter(currentLast)
74-
const tokenToLineBreakAfter =
75-
tokenAfterLastToken.value === ',' ? tokenAfterLastToken : currentLast
76-
77-
return fixer.insertTextAfter(tokenToLineBreakAfter, '\n')
78-
}
79-
}
80-
81-
/**
82-
* Checks if there is an empty line between two tokens
83-
* @param {Token} first The first token
84-
* @param {Token} second The second token
85-
* @returns {boolean} True if there is at least a line between the tokens
86-
*/
87-
function isPaddingBetweenTokens(first, second) {
88-
const comments = sourceCode.getCommentsBefore(second)
89-
const len = comments.length
90-
91-
// If there is no comments
92-
if (len === 0) {
93-
const linesBetweenFstAndSnd =
94-
second.loc.start.line - first.loc.end.line - 1
95-
96-
return linesBetweenFstAndSnd >= 1
97-
}
98-
99-
// If there are comments
100-
let sumOfCommentLines = 0 // the numbers of lines of comments
101-
let prevCommentLineNum = -1 // line number of the end of the previous comment
102-
103-
for (let i = 0; i < len; i++) {
104-
const commentLinesOfThisComment =
105-
comments[i].loc.end.line - comments[i].loc.start.line + 1
106-
107-
sumOfCommentLines += commentLinesOfThisComment
108-
109-
/*
110-
* If this comment and the previous comment are in the same line,
111-
* the count of comment lines is duplicated. So decrement sumOfCommentLines.
112-
*/
113-
if (prevCommentLineNum === comments[i].loc.start.line) {
114-
sumOfCommentLines -= 1
115-
}
116-
117-
prevCommentLineNum = comments[i].loc.end.line
118-
}
119-
120-
/*
121-
* If the first block and the first comment are in the same line,
122-
* the count of comment lines is duplicated. So decrement sumOfCommentLines.
123-
*/
124-
if (first.loc.end.line === comments[0].loc.start.line) {
125-
sumOfCommentLines -= 1
67+
always(fixer, endOfCurrent /*, startOfNext*/) {
68+
return fixer.insertTextAfterRange([0, endOfCurrent], '\n')
12669
}
127-
128-
/*
129-
* If the last comment and the second block are in the same line,
130-
* the count of comment lines is duplicated. So decrement sumOfCommentLines.
131-
*/
132-
if (comments[len - 1].loc.end.line === second.loc.start.line) {
133-
sumOfCommentLines -= 1
134-
}
135-
136-
const linesBetweenFstAndSnd =
137-
second.loc.start.line - first.loc.end.line - 1
138-
139-
return linesBetweenFstAndSnd - sumOfCommentLines >= 1
14070
}
14171

14272
/**
143-
* Report error based on configuration
73+
* Report error based on configuration.
74+
*
14475
* @param {ASTNode} node Where to report errors
14576
* @param {boolean} isPadded True if the option is followed by an empty line
146-
* @param {Token} currentLast End of checked token
147-
* @param {Token} nextFirst Start of next token
77+
* @param {number} endOfCurrent End of checked token
78+
* @param {number} startOfNext Start of next token
14879
*/
149-
function reportError(node, isPadded, currentLast, nextFirst) {
80+
function reportError(node, isPadded, endOfCurrent, startOfNext) {
15081
const key = isPadded ? 'never' : 'always'
15182
const fixFunction = fixFunctions[key]
15283

15384
context.report({
15485
node,
15586
messageId: key,
156-
fix: (fixer) => fixFunction(fixer, currentLast, nextFirst)
87+
fix: (fixer) => fixFunction(fixer, endOfCurrent, startOfNext)
15788
})
15889
}
15990

16091
/**
161-
* Compares options and decides what to do
162-
* @param {ASTNode} option current option to check
163-
* @param {ASTNode} nextNode next node to check against
92+
* Compares options and decides what to do.
93+
* This takes into account comments before options, but not empty lines between multiple comments.
94+
*
95+
* @param {ASTNode} current current option to check
96+
* @param {ASTNode} next next node to check against
16497
*/
165-
function checkOption(option, nextNode) {
166-
const currentLast = sourceCode.getLastToken(option)
167-
const nextFirst = sourceCode.getFirstToken(nextNode)
168-
const isPadded = isPaddingBetweenTokens(currentLast, nextFirst)
98+
function checkOption(current, next) {
99+
const endOfCurrent =
100+
sourceCode.getIndexFromLoc({
101+
line: current.loc.end.line + 1,
102+
column: 0
103+
}) - 1 /* start of next line, -1 for previous line */
104+
105+
const comments = sourceCode.getCommentsBefore(next)
106+
const nextNode = comments.length ? comments[0] : next
107+
108+
const startOfNext = sourceCode.getIndexFromLoc({
109+
line: nextNode.loc.start.line,
110+
column: 0
111+
})
169112

113+
const isPadded = startOfNext !== endOfCurrent + 1
170114
if (shouldPad === isPadded) {
171115
return
172116
}
173117

174-
reportError(nextNode, isPadded, currentLast, nextFirst)
118+
reportError(next, isPadded, endOfCurrent, startOfNext)
175119
}
176120

177121
return {

tests/lib/rules/empty-line-between-options.js

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,26 +100,96 @@ tester.run('empty-line-between-options', rule, {
100100
`,
101101
errors: [
102102
{
103-
message: 'Expected blank line between Vue component options.',
103+
message: rule.meta.messages.always,
104104
line: 12,
105105
column: 9
106106
},
107107
{
108-
message: 'Expected blank line between Vue component options.',
108+
message: rule.meta.messages.always,
109109
line: 15,
110110
column: 19
111111
},
112112
{
113-
message: 'Expected blank line between Vue component options.',
113+
message: rule.meta.messages.always,
114114
line: 16,
115115
column: 9
116116
},
117117
{
118-
message: 'Expected blank line between Vue component options.',
118+
message: rule.meta.messages.always,
119119
line: 19,
120120
column: 9
121121
}
122122
]
123+
},
124+
{
125+
filename: 'test-never.vue',
126+
code: `
127+
<template></template>
128+
129+
<script>
130+
export default {
131+
name: 'AComponentOfSorts',
132+
133+
/**
134+
* @return {Object}
135+
*/
136+
data(){
137+
return {}
138+
},
139+
140+
/* red */ i18n: {},
141+
142+
config: {} /* green */,
143+
144+
/* who */ /* writes */
145+
/* comments like this */
146+
computed: {}
147+
}
148+
</script>
149+
`,
150+
output: `
151+
<template></template>
152+
153+
<script>
154+
export default {
155+
name: 'AComponentOfSorts',
156+
/**
157+
* @return {Object}
158+
*/
159+
data(){
160+
return {}
161+
},
162+
/* red */ i18n: {},
163+
config: {} /* green */,
164+
/* who */ /* writes */
165+
/* comments like this */
166+
computed: {}
167+
}
168+
</script>
169+
`,
170+
errors: [
171+
{
172+
message: rule.meta.messages.never,
173+
line: 11,
174+
column: 9
175+
},
176+
{
177+
message: rule.meta.messages.never,
178+
line: 15,
179+
column: 19
180+
},
181+
{
182+
message: rule.meta.messages.never,
183+
line: 17,
184+
column: 9
185+
},
186+
{
187+
message: rule.meta.messages.never,
188+
line: 21,
189+
column: 9
190+
}
191+
],
192+
options: ['never']
123193
}
124194
]
125195
})

0 commit comments

Comments
 (0)