eslint 6.6.0 → 6.8.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.
- package/CHANGELOG.md +94 -0
- package/README.md +7 -8
- package/conf/config-schema.js +2 -0
- package/conf/default-cli-options.js +1 -1
- package/conf/eslint-recommended.js +0 -1
- package/lib/cli-engine/cascading-config-array-factory.js +38 -13
- package/lib/cli-engine/cli-engine.js +41 -14
- package/lib/cli-engine/config-array/config-array.js +13 -0
- package/lib/cli-engine/config-array/extracted-config.js +27 -0
- package/lib/cli-engine/config-array/ignore-pattern.js +231 -0
- package/lib/cli-engine/config-array/index.js +2 -0
- package/lib/cli-engine/config-array-factory.js +115 -1
- package/lib/cli-engine/file-enumerator.js +73 -40
- package/lib/cli-engine/lint-result-cache.js +2 -1
- package/lib/cli.js +2 -1
- package/lib/init/config-initializer.js +4 -3
- package/lib/linter/config-comment-parser.js +1 -1
- package/lib/linter/report-translator.js +73 -7
- package/lib/options.js +6 -0
- package/lib/rule-tester/rule-tester.js +42 -6
- package/lib/rules/array-bracket-spacing.js +8 -8
- package/lib/rules/camelcase.js +19 -6
- package/lib/rules/comma-dangle.js +5 -2
- package/lib/rules/computed-property-spacing.js +4 -4
- package/lib/rules/curly.js +9 -4
- package/lib/rules/function-call-argument-newline.js +3 -1
- package/lib/rules/grouped-accessor-pairs.js +224 -0
- package/lib/rules/indent.js +11 -0
- package/lib/rules/index.js +5 -0
- package/lib/rules/key-spacing.js +34 -15
- package/lib/rules/lines-between-class-members.js +42 -53
- package/lib/rules/multiline-comment-style.js +237 -106
- package/lib/rules/no-cond-assign.js +14 -4
- package/lib/rules/no-constructor-return.js +62 -0
- package/lib/rules/no-dupe-else-if.js +122 -0
- package/lib/rules/no-implicit-globals.js +90 -8
- package/lib/rules/no-inline-comments.js +25 -11
- package/lib/rules/no-invalid-this.js +16 -2
- package/lib/rules/no-multiple-empty-lines.js +1 -1
- package/lib/rules/no-octal-escape.js +1 -1
- package/lib/rules/no-restricted-imports.js +2 -2
- package/lib/rules/no-setter-return.js +227 -0
- package/lib/rules/no-underscore-dangle.js +23 -4
- package/lib/rules/no-unexpected-multiline.js +8 -0
- package/lib/rules/no-unsafe-negation.js +30 -5
- package/lib/rules/no-useless-computed-key.js +60 -33
- package/lib/rules/no-useless-escape.js +26 -3
- package/lib/rules/object-curly-spacing.js +8 -8
- package/lib/rules/operator-assignment.js +11 -2
- package/lib/rules/prefer-const.js +14 -7
- package/lib/rules/prefer-exponentiation-operator.js +189 -0
- package/lib/rules/prefer-numeric-literals.js +29 -28
- package/lib/rules/require-atomic-updates.js +1 -1
- package/lib/rules/require-await.js +8 -0
- package/lib/rules/semi.js +6 -3
- package/lib/rules/space-infix-ops.js +1 -1
- package/lib/rules/spaced-comment.js +5 -4
- package/lib/rules/utils/ast-utils.js +31 -4
- package/lib/shared/types.js +9 -0
- package/lib/source-code/source-code.js +87 -10
- package/package.json +4 -3
- package/lib/cli-engine/ignored-paths.js +0 -363
@@ -0,0 +1,224 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Rule to require grouped accessor pairs in object literals and classes
|
3
|
+
* @author Milos Djermanovic
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const astUtils = require("./utils/ast-utils");
|
13
|
+
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Typedefs
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Property name if it can be computed statically, otherwise the list of the tokens of the key node.
|
20
|
+
* @typedef {string|Token[]} Key
|
21
|
+
*/
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Accessor nodes with the same key.
|
25
|
+
* @typedef {Object} AccessorData
|
26
|
+
* @property {Key} key Accessor's key
|
27
|
+
* @property {ASTNode[]} getters List of getter nodes.
|
28
|
+
* @property {ASTNode[]} setters List of setter nodes.
|
29
|
+
*/
|
30
|
+
|
31
|
+
//------------------------------------------------------------------------------
|
32
|
+
// Helpers
|
33
|
+
//------------------------------------------------------------------------------
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Checks whether or not the given lists represent the equal tokens in the same order.
|
37
|
+
* Tokens are compared by their properties, not by instance.
|
38
|
+
* @param {Token[]} left First list of tokens.
|
39
|
+
* @param {Token[]} right Second list of tokens.
|
40
|
+
* @returns {boolean} `true` if the lists have same tokens.
|
41
|
+
*/
|
42
|
+
function areEqualTokenLists(left, right) {
|
43
|
+
if (left.length !== right.length) {
|
44
|
+
return false;
|
45
|
+
}
|
46
|
+
|
47
|
+
for (let i = 0; i < left.length; i++) {
|
48
|
+
const leftToken = left[i],
|
49
|
+
rightToken = right[i];
|
50
|
+
|
51
|
+
if (leftToken.type !== rightToken.type || leftToken.value !== rightToken.value) {
|
52
|
+
return false;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
return true;
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Checks whether or not the given keys are equal.
|
61
|
+
* @param {Key} left First key.
|
62
|
+
* @param {Key} right Second key.
|
63
|
+
* @returns {boolean} `true` if the keys are equal.
|
64
|
+
*/
|
65
|
+
function areEqualKeys(left, right) {
|
66
|
+
if (typeof left === "string" && typeof right === "string") {
|
67
|
+
|
68
|
+
// Statically computed names.
|
69
|
+
return left === right;
|
70
|
+
}
|
71
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
72
|
+
|
73
|
+
// Token lists.
|
74
|
+
return areEqualTokenLists(left, right);
|
75
|
+
}
|
76
|
+
|
77
|
+
return false;
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Checks whether or not a given node is of an accessor kind ('get' or 'set').
|
82
|
+
* @param {ASTNode} node A node to check.
|
83
|
+
* @returns {boolean} `true` if the node is of an accessor kind.
|
84
|
+
*/
|
85
|
+
function isAccessorKind(node) {
|
86
|
+
return node.kind === "get" || node.kind === "set";
|
87
|
+
}
|
88
|
+
|
89
|
+
//------------------------------------------------------------------------------
|
90
|
+
// Rule Definition
|
91
|
+
//------------------------------------------------------------------------------
|
92
|
+
|
93
|
+
module.exports = {
|
94
|
+
meta: {
|
95
|
+
type: "suggestion",
|
96
|
+
|
97
|
+
docs: {
|
98
|
+
description: "require grouped accessor pairs in object literals and classes",
|
99
|
+
category: "Best Practices",
|
100
|
+
recommended: false,
|
101
|
+
url: "https://eslint.org/docs/rules/grouped-accessor-pairs"
|
102
|
+
},
|
103
|
+
|
104
|
+
schema: [
|
105
|
+
{
|
106
|
+
enum: ["anyOrder", "getBeforeSet", "setBeforeGet"]
|
107
|
+
}
|
108
|
+
],
|
109
|
+
|
110
|
+
messages: {
|
111
|
+
notGrouped: "Accessor pair {{ formerName }} and {{ latterName }} should be grouped.",
|
112
|
+
invalidOrder: "Expected {{ latterName }} to be before {{ formerName }}."
|
113
|
+
}
|
114
|
+
},
|
115
|
+
|
116
|
+
create(context) {
|
117
|
+
const order = context.options[0] || "anyOrder";
|
118
|
+
const sourceCode = context.getSourceCode();
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Reports the given accessor pair.
|
122
|
+
* @param {string} messageId messageId to report.
|
123
|
+
* @param {ASTNode} formerNode getter/setter node that is defined before `latterNode`.
|
124
|
+
* @param {ASTNode} latterNode getter/setter node that is defined after `formerNode`.
|
125
|
+
* @returns {void}
|
126
|
+
* @private
|
127
|
+
*/
|
128
|
+
function report(messageId, formerNode, latterNode) {
|
129
|
+
context.report({
|
130
|
+
node: latterNode,
|
131
|
+
messageId,
|
132
|
+
loc: astUtils.getFunctionHeadLoc(latterNode.value, sourceCode),
|
133
|
+
data: {
|
134
|
+
formerName: astUtils.getFunctionNameWithKind(formerNode.value),
|
135
|
+
latterName: astUtils.getFunctionNameWithKind(latterNode.value)
|
136
|
+
}
|
137
|
+
});
|
138
|
+
}
|
139
|
+
|
140
|
+
/**
|
141
|
+
* Creates a new `AccessorData` object for the given getter or setter node.
|
142
|
+
* @param {ASTNode} node A getter or setter node.
|
143
|
+
* @returns {AccessorData} New `AccessorData` object that contains the given node.
|
144
|
+
* @private
|
145
|
+
*/
|
146
|
+
function createAccessorData(node) {
|
147
|
+
const name = astUtils.getStaticPropertyName(node);
|
148
|
+
const key = (name !== null) ? name : sourceCode.getTokens(node.key);
|
149
|
+
|
150
|
+
return {
|
151
|
+
key,
|
152
|
+
getters: node.kind === "get" ? [node] : [],
|
153
|
+
setters: node.kind === "set" ? [node] : []
|
154
|
+
};
|
155
|
+
}
|
156
|
+
|
157
|
+
/**
|
158
|
+
* Merges the given `AccessorData` object into the given accessors list.
|
159
|
+
* @param {AccessorData[]} accessors The list to merge into.
|
160
|
+
* @param {AccessorData} accessorData The object to merge.
|
161
|
+
* @returns {AccessorData[]} The same instance with the merged object.
|
162
|
+
* @private
|
163
|
+
*/
|
164
|
+
function mergeAccessorData(accessors, accessorData) {
|
165
|
+
const equalKeyElement = accessors.find(a => areEqualKeys(a.key, accessorData.key));
|
166
|
+
|
167
|
+
if (equalKeyElement) {
|
168
|
+
equalKeyElement.getters.push(...accessorData.getters);
|
169
|
+
equalKeyElement.setters.push(...accessorData.setters);
|
170
|
+
} else {
|
171
|
+
accessors.push(accessorData);
|
172
|
+
}
|
173
|
+
|
174
|
+
return accessors;
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Checks accessor pairs in the given list of nodes.
|
179
|
+
* @param {ASTNode[]} nodes The list to check.
|
180
|
+
* @param {Function} shouldCheck – Predicate that returns `true` if the node should be checked.
|
181
|
+
* @returns {void}
|
182
|
+
* @private
|
183
|
+
*/
|
184
|
+
function checkList(nodes, shouldCheck) {
|
185
|
+
const accessors = nodes
|
186
|
+
.filter(shouldCheck)
|
187
|
+
.filter(isAccessorKind)
|
188
|
+
.map(createAccessorData)
|
189
|
+
.reduce(mergeAccessorData, []);
|
190
|
+
|
191
|
+
for (const { getters, setters } of accessors) {
|
192
|
+
|
193
|
+
// Don't report accessor properties that have duplicate getters or setters.
|
194
|
+
if (getters.length === 1 && setters.length === 1) {
|
195
|
+
const [getter] = getters,
|
196
|
+
[setter] = setters,
|
197
|
+
getterIndex = nodes.indexOf(getter),
|
198
|
+
setterIndex = nodes.indexOf(setter),
|
199
|
+
formerNode = getterIndex < setterIndex ? getter : setter,
|
200
|
+
latterNode = getterIndex < setterIndex ? setter : getter;
|
201
|
+
|
202
|
+
if (Math.abs(getterIndex - setterIndex) > 1) {
|
203
|
+
report("notGrouped", formerNode, latterNode);
|
204
|
+
} else if (
|
205
|
+
(order === "getBeforeSet" && getterIndex > setterIndex) ||
|
206
|
+
(order === "setBeforeGet" && getterIndex < setterIndex)
|
207
|
+
) {
|
208
|
+
report("invalidOrder", formerNode, latterNode);
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
return {
|
215
|
+
ObjectExpression(node) {
|
216
|
+
checkList(node.properties, n => n.type === "Property");
|
217
|
+
},
|
218
|
+
ClassBody(node) {
|
219
|
+
checkList(node.body, n => n.type === "MethodDefinition" && !n.static);
|
220
|
+
checkList(node.body, n => n.type === "MethodDefinition" && n.static);
|
221
|
+
}
|
222
|
+
};
|
223
|
+
}
|
224
|
+
};
|
package/lib/rules/indent.js
CHANGED
@@ -1492,6 +1492,17 @@ module.exports = {
|
|
1492
1492
|
);
|
1493
1493
|
},
|
1494
1494
|
|
1495
|
+
JSXSpreadAttribute(node) {
|
1496
|
+
const openingCurly = sourceCode.getFirstToken(node);
|
1497
|
+
const closingCurly = sourceCode.getLastToken(node);
|
1498
|
+
|
1499
|
+
offsets.setDesiredOffsets(
|
1500
|
+
[openingCurly.range[1], closingCurly.range[0]],
|
1501
|
+
openingCurly,
|
1502
|
+
1
|
1503
|
+
);
|
1504
|
+
},
|
1505
|
+
|
1495
1506
|
"*"(node) {
|
1496
1507
|
const firstToken = sourceCode.getFirstToken(node);
|
1497
1508
|
|
package/lib/rules/index.js
CHANGED
@@ -52,6 +52,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
52
52
|
"generator-star-spacing": () => require("./generator-star-spacing"),
|
53
53
|
"getter-return": () => require("./getter-return"),
|
54
54
|
"global-require": () => require("./global-require"),
|
55
|
+
"grouped-accessor-pairs": () => require("./grouped-accessor-pairs"),
|
55
56
|
"guard-for-in": () => require("./guard-for-in"),
|
56
57
|
"handle-callback-err": () => require("./handle-callback-err"),
|
57
58
|
"id-blacklist": () => require("./id-blacklist"),
|
@@ -101,6 +102,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
101
102
|
"no-console": () => require("./no-console"),
|
102
103
|
"no-const-assign": () => require("./no-const-assign"),
|
103
104
|
"no-constant-condition": () => require("./no-constant-condition"),
|
105
|
+
"no-constructor-return": () => require("./no-constructor-return"),
|
104
106
|
"no-continue": () => require("./no-continue"),
|
105
107
|
"no-control-regex": () => require("./no-control-regex"),
|
106
108
|
"no-debugger": () => require("./no-debugger"),
|
@@ -108,6 +110,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
108
110
|
"no-div-regex": () => require("./no-div-regex"),
|
109
111
|
"no-dupe-args": () => require("./no-dupe-args"),
|
110
112
|
"no-dupe-class-members": () => require("./no-dupe-class-members"),
|
113
|
+
"no-dupe-else-if": () => require("./no-dupe-else-if"),
|
111
114
|
"no-dupe-keys": () => require("./no-dupe-keys"),
|
112
115
|
"no-duplicate-case": () => require("./no-duplicate-case"),
|
113
116
|
"no-duplicate-imports": () => require("./no-duplicate-imports"),
|
@@ -186,6 +189,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
186
189
|
"no-self-assign": () => require("./no-self-assign"),
|
187
190
|
"no-self-compare": () => require("./no-self-compare"),
|
188
191
|
"no-sequences": () => require("./no-sequences"),
|
192
|
+
"no-setter-return": () => require("./no-setter-return"),
|
189
193
|
"no-shadow": () => require("./no-shadow"),
|
190
194
|
"no-shadow-restricted-names": () => require("./no-shadow-restricted-names"),
|
191
195
|
"no-spaced-func": () => require("./no-spaced-func"),
|
@@ -238,6 +242,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
238
242
|
"prefer-arrow-callback": () => require("./prefer-arrow-callback"),
|
239
243
|
"prefer-const": () => require("./prefer-const"),
|
240
244
|
"prefer-destructuring": () => require("./prefer-destructuring"),
|
245
|
+
"prefer-exponentiation-operator": () => require("./prefer-exponentiation-operator"),
|
241
246
|
"prefer-named-capture-group": () => require("./prefer-named-capture-group"),
|
242
247
|
"prefer-numeric-literals": () => require("./prefer-numeric-literals"),
|
243
248
|
"prefer-object-spread": () => require("./prefer-object-spread"),
|
package/lib/rules/key-spacing.js
CHANGED
@@ -42,6 +42,18 @@ function isSingleLine(node) {
|
|
42
42
|
return (node.loc.end.line === node.loc.start.line);
|
43
43
|
}
|
44
44
|
|
45
|
+
/**
|
46
|
+
* Checks whether the properties on a single line.
|
47
|
+
* @param {ASTNode[]} properties List of Property AST nodes.
|
48
|
+
* @returns {boolean} True if all properies is on a single line.
|
49
|
+
*/
|
50
|
+
function isSingleLineProperties(properties) {
|
51
|
+
const [firstProp] = properties,
|
52
|
+
lastProp = last(properties);
|
53
|
+
|
54
|
+
return firstProp.loc.start.line === lastProp.loc.end.line;
|
55
|
+
}
|
56
|
+
|
45
57
|
/**
|
46
58
|
* Initializes a single option property from the configuration with defaults for undefined values
|
47
59
|
* @param {Object} toOptions Object to be initialized
|
@@ -583,17 +595,6 @@ module.exports = {
|
|
583
595
|
}
|
584
596
|
}
|
585
597
|
|
586
|
-
/**
|
587
|
-
* Verifies vertical alignment, taking into account groups of properties.
|
588
|
-
* @param {ASTNode} node ObjectExpression node being evaluated.
|
589
|
-
* @returns {void}
|
590
|
-
*/
|
591
|
-
function verifyAlignment(node) {
|
592
|
-
createGroups(node).forEach(group => {
|
593
|
-
verifyGroupAlignment(group.filter(isKeyValueProperty));
|
594
|
-
});
|
595
|
-
}
|
596
|
-
|
597
598
|
/**
|
598
599
|
* Verifies spacing of property conforms to specified options.
|
599
600
|
* @param {ASTNode} node Property node being evaluated.
|
@@ -611,17 +612,35 @@ module.exports = {
|
|
611
612
|
|
612
613
|
/**
|
613
614
|
* Verifies spacing of each property in a list.
|
614
|
-
* @param
|
615
|
+
* @param {ASTNode[]} properties List of Property AST nodes.
|
616
|
+
* @param {Object} lineOptions Configured singleLine or multiLine options
|
615
617
|
* @returns {void}
|
616
618
|
*/
|
617
|
-
function verifyListSpacing(properties) {
|
619
|
+
function verifyListSpacing(properties, lineOptions) {
|
618
620
|
const length = properties.length;
|
619
621
|
|
620
622
|
for (let i = 0; i < length; i++) {
|
621
|
-
verifySpacing(properties[i],
|
623
|
+
verifySpacing(properties[i], lineOptions);
|
622
624
|
}
|
623
625
|
}
|
624
626
|
|
627
|
+
/**
|
628
|
+
* Verifies vertical alignment, taking into account groups of properties.
|
629
|
+
* @param {ASTNode} node ObjectExpression node being evaluated.
|
630
|
+
* @returns {void}
|
631
|
+
*/
|
632
|
+
function verifyAlignment(node) {
|
633
|
+
createGroups(node).forEach(group => {
|
634
|
+
const properties = group.filter(isKeyValueProperty);
|
635
|
+
|
636
|
+
if (properties.length > 0 && isSingleLineProperties(properties)) {
|
637
|
+
verifyListSpacing(properties, multiLineOptions);
|
638
|
+
} else {
|
639
|
+
verifyGroupAlignment(properties);
|
640
|
+
}
|
641
|
+
});
|
642
|
+
}
|
643
|
+
|
625
644
|
//--------------------------------------------------------------------------
|
626
645
|
// Public API
|
627
646
|
//--------------------------------------------------------------------------
|
@@ -631,7 +650,7 @@ module.exports = {
|
|
631
650
|
return {
|
632
651
|
ObjectExpression(node) {
|
633
652
|
if (isSingleLine(node)) {
|
634
|
-
verifyListSpacing(node.properties.filter(isKeyValueProperty));
|
653
|
+
verifyListSpacing(node.properties.filter(isKeyValueProperty), singleLineOptions);
|
635
654
|
} else {
|
636
655
|
verifyAlignment(node);
|
637
656
|
}
|
@@ -54,62 +54,45 @@ module.exports = {
|
|
54
54
|
const sourceCode = context.getSourceCode();
|
55
55
|
|
56
56
|
/**
|
57
|
-
*
|
58
|
-
* @param {Token}
|
59
|
-
* @param {Token}
|
60
|
-
* @
|
57
|
+
* Return the last token among the consecutive tokens that have no exceed max line difference in between, before the first token in the next member.
|
58
|
+
* @param {Token} prevLastToken The last token in the previous member node.
|
59
|
+
* @param {Token} nextFirstToken The first token in the next member node.
|
60
|
+
* @param {number} maxLine The maximum number of allowed line difference between consecutive tokens.
|
61
|
+
* @returns {Token} The last token among the consecutive tokens.
|
61
62
|
*/
|
62
|
-
function
|
63
|
-
const
|
64
|
-
const len = comments.length;
|
63
|
+
function findLastConsecutiveTokenAfter(prevLastToken, nextFirstToken, maxLine) {
|
64
|
+
const after = sourceCode.getTokenAfter(prevLastToken, { includeComments: true });
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
const linesBetweenFstAndSnd = second.loc.start.line - first.loc.end.line - 1;
|
69
|
-
|
70
|
-
return linesBetweenFstAndSnd >= 1;
|
71
|
-
}
|
72
|
-
|
73
|
-
|
74
|
-
// If there are comments
|
75
|
-
let sumOfCommentLines = 0; // the numbers of lines of comments
|
76
|
-
let prevCommentLineNum = -1; // line number of the end of the previous comment
|
77
|
-
|
78
|
-
for (let i = 0; i < len; i++) {
|
79
|
-
const commentLinesOfThisComment = comments[i].loc.end.line - comments[i].loc.start.line + 1;
|
80
|
-
|
81
|
-
sumOfCommentLines += commentLinesOfThisComment;
|
82
|
-
|
83
|
-
/*
|
84
|
-
* If this comment and the previous comment are in the same line,
|
85
|
-
* the count of comment lines is duplicated. So decrement sumOfCommentLines.
|
86
|
-
*/
|
87
|
-
if (prevCommentLineNum === comments[i].loc.start.line) {
|
88
|
-
sumOfCommentLines -= 1;
|
89
|
-
}
|
90
|
-
|
91
|
-
prevCommentLineNum = comments[i].loc.end.line;
|
66
|
+
if (after !== nextFirstToken && after.loc.start.line - prevLastToken.loc.end.line <= maxLine) {
|
67
|
+
return findLastConsecutiveTokenAfter(after, nextFirstToken, maxLine);
|
92
68
|
}
|
69
|
+
return prevLastToken;
|
70
|
+
}
|
93
71
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
72
|
+
/**
|
73
|
+
* Return the first token among the consecutive tokens that have no exceed max line difference in between, after the last token in the previous member.
|
74
|
+
* @param {Token} nextFirstToken The first token in the next member node.
|
75
|
+
* @param {Token} prevLastToken The last token in the previous member node.
|
76
|
+
* @param {number} maxLine The maximum number of allowed line difference between consecutive tokens.
|
77
|
+
* @returns {Token} The first token among the consecutive tokens.
|
78
|
+
*/
|
79
|
+
function findFirstConsecutiveTokenBefore(nextFirstToken, prevLastToken, maxLine) {
|
80
|
+
const before = sourceCode.getTokenBefore(nextFirstToken, { includeComments: true });
|
101
81
|
|
102
|
-
|
103
|
-
|
104
|
-
* the count of comment lines is duplicated. So decrement sumOfCommentLines.
|
105
|
-
*/
|
106
|
-
if (comments[len - 1].loc.end.line === second.loc.start.line) {
|
107
|
-
sumOfCommentLines -= 1;
|
82
|
+
if (before !== prevLastToken && nextFirstToken.loc.start.line - before.loc.end.line <= maxLine) {
|
83
|
+
return findFirstConsecutiveTokenBefore(before, prevLastToken, maxLine);
|
108
84
|
}
|
85
|
+
return nextFirstToken;
|
86
|
+
}
|
109
87
|
|
110
|
-
|
111
|
-
|
112
|
-
|
88
|
+
/**
|
89
|
+
* Checks if there is a token or comment between two tokens.
|
90
|
+
* @param {Token} before The token before.
|
91
|
+
* @param {Token} after The token after.
|
92
|
+
* @returns {boolean} True if there is a token or comment between two tokens.
|
93
|
+
*/
|
94
|
+
function hasTokenOrCommentBetween(before, after) {
|
95
|
+
return sourceCode.getTokensBetween(before, after, { includeComments: true }).length !== 0;
|
113
96
|
}
|
114
97
|
|
115
98
|
return {
|
@@ -120,10 +103,13 @@ module.exports = {
|
|
120
103
|
const curFirst = sourceCode.getFirstToken(body[i]);
|
121
104
|
const curLast = sourceCode.getLastToken(body[i]);
|
122
105
|
const nextFirst = sourceCode.getFirstToken(body[i + 1]);
|
123
|
-
const isPadded = isPaddingBetweenTokens(curLast, nextFirst);
|
124
106
|
const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast);
|
125
107
|
const skip = !isMulti && options[1].exceptAfterSingleLine;
|
126
|
-
|
108
|
+
const beforePadding = findLastConsecutiveTokenAfter(curLast, nextFirst, 1);
|
109
|
+
const afterPadding = findFirstConsecutiveTokenBefore(nextFirst, curLast, 1);
|
110
|
+
const isPadded = afterPadding.loc.start.line - beforePadding.loc.end.line > 1;
|
111
|
+
const hasTokenInPadding = hasTokenOrCommentBetween(beforePadding, afterPadding);
|
112
|
+
const curLineLastToken = findLastConsecutiveTokenAfter(curLast, nextFirst, 0);
|
127
113
|
|
128
114
|
if ((options[0] === "always" && !skip && !isPadded) ||
|
129
115
|
(options[0] === "never" && isPadded)) {
|
@@ -131,9 +117,12 @@ module.exports = {
|
|
131
117
|
node: body[i + 1],
|
132
118
|
messageId: isPadded ? "never" : "always",
|
133
119
|
fix(fixer) {
|
120
|
+
if (hasTokenInPadding) {
|
121
|
+
return null;
|
122
|
+
}
|
134
123
|
return isPadded
|
135
|
-
? fixer.replaceTextRange([
|
136
|
-
: fixer.insertTextAfter(
|
124
|
+
? fixer.replaceTextRange([beforePadding.range[1], afterPadding.range[0]], "\n")
|
125
|
+
: fixer.insertTextAfter(curLineLastToken, "\n");
|
137
126
|
}
|
138
127
|
});
|
139
128
|
}
|