eslint 7.26.0 → 7.27.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 +13 -0
- package/README.md +7 -2
- package/bin/eslint.js +2 -12
- package/lib/cli-engine/file-enumerator.js +1 -1
- package/lib/cli-engine/formatters/html.js +193 -9
- package/lib/init/autoconfig.js +2 -2
- package/lib/linter/apply-disable-directives.js +15 -3
- package/lib/linter/linter.js +6 -4
- package/lib/linter/node-event-generator.js +43 -6
- package/lib/rule-tester/rule-tester.js +14 -10
- package/lib/rules/comma-dangle.js +16 -7
- package/lib/rules/comma-spacing.js +1 -1
- package/lib/rules/complexity.js +2 -3
- package/lib/rules/consistent-return.js +2 -2
- package/lib/rules/eol-last.js +2 -7
- package/lib/rules/indent.js +8 -9
- package/lib/rules/max-lines-per-function.js +2 -3
- package/lib/rules/max-lines.js +32 -7
- package/lib/rules/max-params.js +2 -3
- package/lib/rules/max-statements.js +2 -3
- package/lib/rules/no-fallthrough.js +2 -8
- package/lib/rules/no-restricted-imports.js +61 -24
- package/lib/rules/no-unused-vars.js +27 -3
- package/lib/rules/no-useless-backreference.js +1 -2
- package/lib/rules/no-useless-computed-key.js +8 -2
- package/lib/rules/no-warning-comments.js +1 -1
- package/lib/rules/object-curly-newline.js +19 -4
- package/lib/rules/spaced-comment.js +2 -2
- package/lib/rules/utils/ast-utils.js +2 -2
- package/lib/shared/deprecation-warnings.js +12 -3
- package/lib/shared/string-utils.js +22 -0
- package/lib/source-code/source-code.js +6 -5
- package/lib/source-code/token-store/utils.js +4 -12
- package/messages/{all-files-ignored.txt → all-files-ignored.js} +10 -2
- package/messages/extend-config-missing.js +13 -0
- package/messages/failed-to-read-json.js +11 -0
- package/messages/file-not-found.js +10 -0
- package/messages/{no-config-found.txt → no-config-found.js} +9 -1
- package/messages/plugin-conflict.js +22 -0
- package/messages/plugin-invalid.js +16 -0
- package/messages/plugin-missing.js +19 -0
- package/messages/{print-config-with-directory-path.txt → print-config-with-directory-path.js} +6 -0
- package/messages/whitespace-found.js +11 -0
- package/package.json +5 -4
- package/lib/cli-engine/formatters/html-template-message.html +0 -8
- package/lib/cli-engine/formatters/html-template-page.html +0 -115
- package/lib/cli-engine/formatters/html-template-result.html +0 -6
- package/messages/extend-config-missing.txt +0 -5
- package/messages/failed-to-read-json.txt +0 -3
- package/messages/file-not-found.txt +0 -2
- package/messages/plugin-conflict.txt +0 -7
- package/messages/plugin-invalid.txt +0 -8
- package/messages/plugin-missing.txt +0 -11
- package/messages/whitespace-found.txt +0 -3
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
v7.27.0 - May 21, 2021
|
2
|
+
|
3
|
+
* [`2c0868c`](https://github.com/eslint/eslint/commit/2c0868cbeadc9f42716fa1178ebdc6b4cee6d31e) Chore: merge all html formatter files into `html.js` (#14612) (Milos Djermanovic)
|
4
|
+
* [`9e9b5e0`](https://github.com/eslint/eslint/commit/9e9b5e07475564813b62cd1d7562a93c5fb4bc74) Update: no-unused-vars false negative with comma operator (fixes #14325) (#14354) (Nitin Kumar)
|
5
|
+
* [`afe9569`](https://github.com/eslint/eslint/commit/afe95693e1e4316a1c6f01d39345061d4c5921c7) Chore: use includes instead of indexOf (#14607) (Mikhail Bodrov)
|
6
|
+
* [`c0f418e`](https://github.com/eslint/eslint/commit/c0f418e2476df98519bc156b81d20431984e8704) Chore: Remove lodash (#14287) (Stephen Wade)
|
7
|
+
* [`52655dd`](https://github.com/eslint/eslint/commit/52655dd54925ee02af2ba3a0ebc09de959ae3101) Update: no-restricted-imports custom message for patterns (fixes #11843) (#14580) (Alex Holden)
|
8
|
+
* [`967b1c4`](https://github.com/eslint/eslint/commit/967b1c4ceca8f5248378477da94ff118dafaa647) Chore: Fix typo in large.js (#14589) (Ikko Ashimine)
|
9
|
+
* [`2466a05`](https://github.com/eslint/eslint/commit/2466a05160de60958457d984b79fd445c12ebc98) Sponsors: Sync README with website (ESLint Jenkins)
|
10
|
+
* [`fe29f18`](https://github.com/eslint/eslint/commit/fe29f18227fd02fd7c3da033417d621275b00d0a) Sponsors: Sync README with website (ESLint Jenkins)
|
11
|
+
* [`086c1d6`](https://github.com/eslint/eslint/commit/086c1d6e8593cf8e7851daa8f2a890c213cf6999) Chore: add more test cases for `no-sequences` (#14579) (Nitin Kumar)
|
12
|
+
* [`6a2ced8`](https://github.com/eslint/eslint/commit/6a2ced892c0dc43fa4942293b9f1c4b9151c3741) Docs: Update README team and sponsors (ESLint Jenkins)
|
13
|
+
|
1
14
|
v7.26.0 - May 7, 2021
|
2
15
|
|
3
16
|
* [`aaf65e6`](https://github.com/eslint/eslint/commit/aaf65e629adb74401092c3ccc9cb4e4bd1c8609b) Upgrade: eslintrc for ModuleResolver fix (#14577) (Brandon Mills)
|
package/README.md
CHANGED
@@ -240,6 +240,11 @@ Milos Djermanovic
|
|
240
240
|
The people who review and implement new features.
|
241
241
|
|
242
242
|
<table><tbody><tr><td align="center" valign="top" width="11%">
|
243
|
+
<a href="https://github.com/mysticatea">
|
244
|
+
<img src="https://github.com/mysticatea.png?s=75" width="75" height="75"><br />
|
245
|
+
Toru Nagashima
|
246
|
+
</a>
|
247
|
+
</td><td align="center" valign="top" width="11%">
|
243
248
|
<a href="https://github.com/aladdin-add">
|
244
249
|
<img src="https://github.com/aladdin-add.png?s=75" width="75" height="75"><br />
|
245
250
|
薛定谔的猫
|
@@ -281,9 +286,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
281
286
|
<!--sponsorsstart-->
|
282
287
|
<h3>Platinum Sponsors</h3>
|
283
288
|
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
|
284
|
-
<p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://
|
289
|
+
<p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
|
285
290
|
<p><a href="https://retool.com/"><img src="https://images.opencollective.com/retool/98ea68e/logo.png" alt="Retool" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
|
286
|
-
<p><a href="https://
|
291
|
+
<p><a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a></p>
|
287
292
|
<!--sponsorsend-->
|
288
293
|
|
289
294
|
## <a name="technology-sponsors"></a>Technology Sponsors
|
package/bin/eslint.js
CHANGED
@@ -66,11 +66,8 @@ function readStdin() {
|
|
66
66
|
*/
|
67
67
|
function getErrorMessage(error) {
|
68
68
|
|
69
|
-
// Lazy loading because
|
70
|
-
const fs = require("fs");
|
71
|
-
const path = require("path");
|
69
|
+
// Lazy loading because this is used only if an error happened.
|
72
70
|
const util = require("util");
|
73
|
-
const lodash = require("lodash");
|
74
71
|
|
75
72
|
// Foolproof -- thirdparty module might throw non-object.
|
76
73
|
if (typeof error !== "object" || error === null) {
|
@@ -80,14 +77,7 @@ function getErrorMessage(error) {
|
|
80
77
|
// Use templates if `error.messageTemplate` is present.
|
81
78
|
if (typeof error.messageTemplate === "string") {
|
82
79
|
try {
|
83
|
-
const
|
84
|
-
__dirname,
|
85
|
-
`../messages/${error.messageTemplate}.txt`
|
86
|
-
);
|
87
|
-
|
88
|
-
// Use sync API because Node.js should exit at this tick.
|
89
|
-
const templateText = fs.readFileSync(templateFilePath, "utf-8");
|
90
|
-
const template = lodash.template(templateText);
|
80
|
+
const template = require(`../messages/${error.messageTemplate}.js`);
|
91
81
|
|
92
82
|
return template(error.messageData || {});
|
93
83
|
} catch {
|
@@ -38,7 +38,7 @@ const fs = require("fs");
|
|
38
38
|
const path = require("path");
|
39
39
|
const getGlobParent = require("glob-parent");
|
40
40
|
const isGlob = require("is-glob");
|
41
|
-
const
|
41
|
+
const escapeRegExp = require("escape-string-regexp");
|
42
42
|
const { Minimatch } = require("minimatch");
|
43
43
|
|
44
44
|
const {
|
@@ -4,17 +4,153 @@
|
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
|
-
const lodash = require("lodash");
|
8
|
-
const fs = require("fs");
|
9
|
-
const path = require("path");
|
10
|
-
|
11
7
|
//------------------------------------------------------------------------------
|
12
8
|
// Helpers
|
13
9
|
//------------------------------------------------------------------------------
|
14
10
|
|
15
|
-
const
|
16
|
-
const
|
17
|
-
|
11
|
+
const encodeHTML = (function() {
|
12
|
+
const encodeHTMLRules = {
|
13
|
+
"&": "&",
|
14
|
+
"<": "<",
|
15
|
+
">": ">",
|
16
|
+
'"': """,
|
17
|
+
"'": "'"
|
18
|
+
};
|
19
|
+
const matchHTML = /[&<>"']/ug;
|
20
|
+
|
21
|
+
return function(code) {
|
22
|
+
return code
|
23
|
+
? code.toString().replace(matchHTML, m => encodeHTMLRules[m] || m)
|
24
|
+
: "";
|
25
|
+
};
|
26
|
+
}());
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Get the final HTML document.
|
30
|
+
* @param {Object} it data for the document.
|
31
|
+
* @returns {string} HTML document.
|
32
|
+
*/
|
33
|
+
function pageTemplate(it) {
|
34
|
+
const { reportColor, reportSummary, date, results } = it;
|
35
|
+
|
36
|
+
return `
|
37
|
+
<!DOCTYPE html>
|
38
|
+
<html>
|
39
|
+
<head>
|
40
|
+
<meta charset="UTF-8">
|
41
|
+
<title>ESLint Report</title>
|
42
|
+
<style>
|
43
|
+
body {
|
44
|
+
font-family:Arial, "Helvetica Neue", Helvetica, sans-serif;
|
45
|
+
font-size:16px;
|
46
|
+
font-weight:normal;
|
47
|
+
margin:0;
|
48
|
+
padding:0;
|
49
|
+
color:#333
|
50
|
+
}
|
51
|
+
#overview {
|
52
|
+
padding:20px 30px
|
53
|
+
}
|
54
|
+
td, th {
|
55
|
+
padding:5px 10px
|
56
|
+
}
|
57
|
+
h1 {
|
58
|
+
margin:0
|
59
|
+
}
|
60
|
+
table {
|
61
|
+
margin:30px;
|
62
|
+
width:calc(100% - 60px);
|
63
|
+
max-width:1000px;
|
64
|
+
border-radius:5px;
|
65
|
+
border:1px solid #ddd;
|
66
|
+
border-spacing:0px;
|
67
|
+
}
|
68
|
+
th {
|
69
|
+
font-weight:400;
|
70
|
+
font-size:medium;
|
71
|
+
text-align:left;
|
72
|
+
cursor:pointer
|
73
|
+
}
|
74
|
+
td.clr-1, td.clr-2, th span {
|
75
|
+
font-weight:700
|
76
|
+
}
|
77
|
+
th span {
|
78
|
+
float:right;
|
79
|
+
margin-left:20px
|
80
|
+
}
|
81
|
+
th span:after {
|
82
|
+
content:"";
|
83
|
+
clear:both;
|
84
|
+
display:block
|
85
|
+
}
|
86
|
+
tr:last-child td {
|
87
|
+
border-bottom:none
|
88
|
+
}
|
89
|
+
tr td:first-child, tr td:last-child {
|
90
|
+
color:#9da0a4
|
91
|
+
}
|
92
|
+
#overview.bg-0, tr.bg-0 th {
|
93
|
+
color:#468847;
|
94
|
+
background:#dff0d8;
|
95
|
+
border-bottom:1px solid #d6e9c6
|
96
|
+
}
|
97
|
+
#overview.bg-1, tr.bg-1 th {
|
98
|
+
color:#f0ad4e;
|
99
|
+
background:#fcf8e3;
|
100
|
+
border-bottom:1px solid #fbeed5
|
101
|
+
}
|
102
|
+
#overview.bg-2, tr.bg-2 th {
|
103
|
+
color:#b94a48;
|
104
|
+
background:#f2dede;
|
105
|
+
border-bottom:1px solid #eed3d7
|
106
|
+
}
|
107
|
+
td {
|
108
|
+
border-bottom:1px solid #ddd
|
109
|
+
}
|
110
|
+
td.clr-1 {
|
111
|
+
color:#f0ad4e
|
112
|
+
}
|
113
|
+
td.clr-2 {
|
114
|
+
color:#b94a48
|
115
|
+
}
|
116
|
+
td a {
|
117
|
+
color:#3a33d1;
|
118
|
+
text-decoration:none
|
119
|
+
}
|
120
|
+
td a:hover {
|
121
|
+
color:#272296;
|
122
|
+
text-decoration:underline
|
123
|
+
}
|
124
|
+
</style>
|
125
|
+
</head>
|
126
|
+
<body>
|
127
|
+
<div id="overview" class="bg-${reportColor}">
|
128
|
+
<h1>ESLint Report</h1>
|
129
|
+
<div>
|
130
|
+
<span>${reportSummary}</span> - Generated on ${date}
|
131
|
+
</div>
|
132
|
+
</div>
|
133
|
+
<table>
|
134
|
+
<tbody>
|
135
|
+
${results}
|
136
|
+
</tbody>
|
137
|
+
</table>
|
138
|
+
<script type="text/javascript">
|
139
|
+
var groups = document.querySelectorAll("tr[data-group]");
|
140
|
+
for (i = 0; i < groups.length; i++) {
|
141
|
+
groups[i].addEventListener("click", function() {
|
142
|
+
var inGroup = document.getElementsByClassName(this.getAttribute("data-group"));
|
143
|
+
this.innerHTML = (this.innerHTML.indexOf("+") > -1) ? this.innerHTML.replace("+", "-") : this.innerHTML.replace("-", "+");
|
144
|
+
for (var j = 0; j < inGroup.length; j++) {
|
145
|
+
inGroup[j].style.display = (inGroup[j].style.display !== "none") ? "none" : "table-row";
|
146
|
+
}
|
147
|
+
});
|
148
|
+
}
|
149
|
+
</script>
|
150
|
+
</body>
|
151
|
+
</html>
|
152
|
+
`.trimLeft();
|
153
|
+
}
|
18
154
|
|
19
155
|
/**
|
20
156
|
* Given a word and a count, append an s if count is not one.
|
@@ -58,6 +194,35 @@ function renderColor(totalErrors, totalWarnings) {
|
|
58
194
|
return 0;
|
59
195
|
}
|
60
196
|
|
197
|
+
/**
|
198
|
+
* Get HTML (table row) describing a single message.
|
199
|
+
* @param {Object} it data for the message.
|
200
|
+
* @returns {string} HTML (table row) describing the message.
|
201
|
+
*/
|
202
|
+
function messageTemplate(it) {
|
203
|
+
const {
|
204
|
+
parentIndex,
|
205
|
+
lineNumber,
|
206
|
+
columnNumber,
|
207
|
+
severityNumber,
|
208
|
+
severityName,
|
209
|
+
message,
|
210
|
+
ruleUrl,
|
211
|
+
ruleId
|
212
|
+
} = it;
|
213
|
+
|
214
|
+
return `
|
215
|
+
<tr style="display:none" class="f-${parentIndex}">
|
216
|
+
<td>${lineNumber}:${columnNumber}</td>
|
217
|
+
<td class="clr-${severityNumber}">${severityName}</td>
|
218
|
+
<td>${encodeHTML(message)}</td>
|
219
|
+
<td>
|
220
|
+
<a href="${ruleUrl ? ruleUrl : ""}" target="_blank" rel="noopener noreferrer">${ruleId ? ruleId : ""}</a>
|
221
|
+
</td>
|
222
|
+
</tr>
|
223
|
+
`.trimLeft();
|
224
|
+
}
|
225
|
+
|
61
226
|
/**
|
62
227
|
* Get HTML (table rows) describing the messages.
|
63
228
|
* @param {Array} messages Messages.
|
@@ -80,7 +245,9 @@ function renderMessages(messages, parentIndex, rulesMeta) {
|
|
80
245
|
if (rulesMeta) {
|
81
246
|
const meta = rulesMeta[message.ruleId];
|
82
247
|
|
83
|
-
|
248
|
+
if (meta && meta.docs && meta.docs.url) {
|
249
|
+
ruleUrl = meta.docs.url;
|
250
|
+
}
|
84
251
|
}
|
85
252
|
|
86
253
|
return messageTemplate({
|
@@ -96,6 +263,24 @@ function renderMessages(messages, parentIndex, rulesMeta) {
|
|
96
263
|
}).join("\n");
|
97
264
|
}
|
98
265
|
|
266
|
+
/**
|
267
|
+
* Get HTML (table row) describing the result for a single file.
|
268
|
+
* @param {Object} it data for the file.
|
269
|
+
* @returns {string} HTML (table row) describing the result for the file.
|
270
|
+
*/
|
271
|
+
function resultTemplate(it) {
|
272
|
+
const { color, index, filePath, summary } = it;
|
273
|
+
|
274
|
+
return `
|
275
|
+
<tr class="bg-${color}" data-group="f-${index}">
|
276
|
+
<th colspan="4">
|
277
|
+
[+] ${encodeHTML(filePath)}
|
278
|
+
<span>${encodeHTML(summary)}</span>
|
279
|
+
</th>
|
280
|
+
</tr>
|
281
|
+
`.trimLeft();
|
282
|
+
}
|
283
|
+
|
99
284
|
// eslint-disable-next-line jsdoc/require-description
|
100
285
|
/**
|
101
286
|
* @param {Array} results Test results.
|
@@ -108,7 +293,6 @@ function renderResults(results, rulesMeta) {
|
|
108
293
|
color: renderColor(result.errorCount, result.warningCount),
|
109
294
|
filePath: result.filePath,
|
110
295
|
summary: renderSummary(result.errorCount, result.warningCount)
|
111
|
-
|
112
296
|
}) + renderMessages(result.messages, index, rulesMeta)).join("\n");
|
113
297
|
}
|
114
298
|
|
package/lib/init/autoconfig.js
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
// Requirements
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
const
|
12
|
+
const equal = require("fast-deep-equal"),
|
13
13
|
recConfig = require("../../conf/eslint-recommended"),
|
14
14
|
ConfigOps = require("@eslint/eslintrc/lib/shared/config-ops"),
|
15
15
|
{ Linter } = require("../linter"),
|
@@ -329,7 +329,7 @@ function extendFromRecommended(config) {
|
|
329
329
|
const recRules = Object.keys(recConfig.rules).filter(ruleId => ConfigOps.isErrorSeverity(recConfig.rules[ruleId]));
|
330
330
|
|
331
331
|
recRules.forEach(ruleId => {
|
332
|
-
if (
|
332
|
+
if (equal(recConfig.rules[ruleId], newConfig.rules[ruleId])) {
|
333
333
|
delete newConfig.rules[ruleId];
|
334
334
|
}
|
335
335
|
});
|
@@ -5,8 +5,6 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
-
const lodash = require("lodash");
|
9
|
-
|
10
8
|
/**
|
11
9
|
* Compares the locations of two objects in a source file
|
12
10
|
* @param {{line: number, column: number}} itemA The first object
|
@@ -124,7 +122,21 @@ module.exports = ({ directives, problems, reportUnusedDisableDirectives = "off"
|
|
124
122
|
.map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
|
125
123
|
.sort(compareLocations);
|
126
124
|
|
127
|
-
|
125
|
+
/**
|
126
|
+
* Returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level.
|
127
|
+
* TODO(stephenwade): Replace this with array.flatMap when we drop support for Node v10
|
128
|
+
* @param {any[]} array The array to process
|
129
|
+
* @param {Function} fn The function to use
|
130
|
+
* @returns {any[]} The result array
|
131
|
+
*/
|
132
|
+
function flatMap(array, fn) {
|
133
|
+
const mapped = array.map(fn);
|
134
|
+
const flattened = [].concat(...mapped);
|
135
|
+
|
136
|
+
return flattened;
|
137
|
+
}
|
138
|
+
|
139
|
+
const lineDirectives = flatMap(directives, directive => {
|
128
140
|
switch (directive.type) {
|
129
141
|
case "disable":
|
130
142
|
case "enable":
|
package/lib/linter/linter.js
CHANGED
@@ -15,7 +15,7 @@ const
|
|
15
15
|
eslintScope = require("eslint-scope"),
|
16
16
|
evk = require("eslint-visitor-keys"),
|
17
17
|
espree = require("espree"),
|
18
|
-
|
18
|
+
merge = require("lodash.merge"),
|
19
19
|
BuiltInEnvironments = require("@eslint/eslintrc/conf/environments"),
|
20
20
|
pkg = require("../../package.json"),
|
21
21
|
astUtils = require("../shared/ast-utils"),
|
@@ -529,8 +529,8 @@ function normalizeVerifyOptions(providedOptions, config) {
|
|
529
529
|
function resolveParserOptions(parserName, providedOptions, enabledEnvironments) {
|
530
530
|
const parserOptionsFromEnv = enabledEnvironments
|
531
531
|
.filter(env => env.parserOptions)
|
532
|
-
.reduce((parserOptions, env) =>
|
533
|
-
const mergedParserOptions =
|
532
|
+
.reduce((parserOptions, env) => merge(parserOptions, env.parserOptions), {});
|
533
|
+
const mergedParserOptions = merge(parserOptionsFromEnv, providedOptions || {});
|
534
534
|
const isModule = mergedParserOptions.sourceType === "module";
|
535
535
|
|
536
536
|
if (isModule) {
|
@@ -1286,7 +1286,9 @@ class Linter {
|
|
1286
1286
|
const filenameToExpose = normalizeFilename(filename);
|
1287
1287
|
const text = ensureText(textOrSourceCode);
|
1288
1288
|
const preprocess = options.preprocess || (rawText => [rawText]);
|
1289
|
-
|
1289
|
+
|
1290
|
+
// TODO(stephenwade): Replace this with array.flat() when we drop support for Node v10
|
1291
|
+
const postprocess = options.postprocess || (array => [].concat(...array));
|
1290
1292
|
const filterCodeBlock =
|
1291
1293
|
options.filterCodeBlock ||
|
1292
1294
|
(blockFilename => blockFilename.endsWith(".js"));
|
@@ -10,7 +10,6 @@
|
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
12
|
const esquery = require("esquery");
|
13
|
-
const lodash = require("lodash");
|
14
13
|
|
15
14
|
//------------------------------------------------------------------------------
|
16
15
|
// Typedefs
|
@@ -32,6 +31,35 @@ const lodash = require("lodash");
|
|
32
31
|
// Helpers
|
33
32
|
//------------------------------------------------------------------------------
|
34
33
|
|
34
|
+
/**
|
35
|
+
* Computes the union of one or more arrays
|
36
|
+
* @param {...any[]} arrays One or more arrays to union
|
37
|
+
* @returns {any[]} The union of the input arrays
|
38
|
+
*/
|
39
|
+
function union(...arrays) {
|
40
|
+
|
41
|
+
// TODO(stephenwade): Replace this with arrays.flat() when we drop support for Node v10
|
42
|
+
return [...new Set([].concat(...arrays))];
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Computes the intersection of one or more arrays
|
47
|
+
* @param {...any[]} arrays One or more arrays to intersect
|
48
|
+
* @returns {any[]} The intersection of the input arrays
|
49
|
+
*/
|
50
|
+
function intersection(...arrays) {
|
51
|
+
if (arrays.length === 0) {
|
52
|
+
return [];
|
53
|
+
}
|
54
|
+
|
55
|
+
let result = [...new Set(arrays[0])];
|
56
|
+
|
57
|
+
for (const array of arrays.slice(1)) {
|
58
|
+
result = result.filter(x => array.includes(x));
|
59
|
+
}
|
60
|
+
return result;
|
61
|
+
}
|
62
|
+
|
35
63
|
/**
|
36
64
|
* Gets the possible types of a selector
|
37
65
|
* @param {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
|
@@ -46,7 +74,7 @@ function getPossibleTypes(parsedSelector) {
|
|
46
74
|
const typesForComponents = parsedSelector.selectors.map(getPossibleTypes);
|
47
75
|
|
48
76
|
if (typesForComponents.every(Boolean)) {
|
49
|
-
return
|
77
|
+
return union(...typesForComponents);
|
50
78
|
}
|
51
79
|
return null;
|
52
80
|
}
|
@@ -63,7 +91,7 @@ function getPossibleTypes(parsedSelector) {
|
|
63
91
|
* If at least one of the components could only match a particular type, the compound could only match
|
64
92
|
* the intersection of those types.
|
65
93
|
*/
|
66
|
-
return
|
94
|
+
return intersection(...typesForComponents);
|
67
95
|
}
|
68
96
|
|
69
97
|
case "child":
|
@@ -166,15 +194,21 @@ function tryParseSelector(rawSelector) {
|
|
166
194
|
}
|
167
195
|
}
|
168
196
|
|
197
|
+
const selectorCache = new Map();
|
198
|
+
|
169
199
|
/**
|
170
200
|
* Parses a raw selector string, and returns the parsed selector along with specificity and type information.
|
171
201
|
* @param {string} rawSelector A raw AST selector
|
172
202
|
* @returns {ASTSelector} A selector descriptor
|
173
203
|
*/
|
174
|
-
|
204
|
+
function parseSelector(rawSelector) {
|
205
|
+
if (selectorCache.has(rawSelector)) {
|
206
|
+
return selectorCache.get(rawSelector);
|
207
|
+
}
|
208
|
+
|
175
209
|
const parsedSelector = tryParseSelector(rawSelector);
|
176
210
|
|
177
|
-
|
211
|
+
const result = {
|
178
212
|
rawSelector,
|
179
213
|
isExit: rawSelector.endsWith(":exit"),
|
180
214
|
parsedSelector,
|
@@ -182,7 +216,10 @@ const parseSelector = lodash.memoize(rawSelector => {
|
|
182
216
|
attributeCount: countClassAttributes(parsedSelector),
|
183
217
|
identifierCount: countIdentifiers(parsedSelector)
|
184
218
|
};
|
185
|
-
|
219
|
+
|
220
|
+
selectorCache.set(rawSelector, result);
|
221
|
+
return result;
|
222
|
+
}
|
186
223
|
|
187
224
|
//------------------------------------------------------------------------------
|
188
225
|
// Public Interface
|
@@ -44,7 +44,8 @@ const
|
|
44
44
|
assert = require("assert"),
|
45
45
|
path = require("path"),
|
46
46
|
util = require("util"),
|
47
|
-
|
47
|
+
merge = require("lodash.merge"),
|
48
|
+
equal = require("fast-deep-equal"),
|
48
49
|
Traverser = require("../../lib/shared/traverser"),
|
49
50
|
{ getRuleOptionsSchema, validate } = require("../shared/config-validator"),
|
50
51
|
{ Linter, SourceCodeFixer, interpolate } = require("../linter");
|
@@ -324,10 +325,9 @@ class RuleTester {
|
|
324
325
|
* configuration and the default configuration.
|
325
326
|
* @type {Object}
|
326
327
|
*/
|
327
|
-
this.testerConfig =
|
328
|
-
|
329
|
-
|
330
|
-
lodash.cloneDeep(defaultConfig),
|
328
|
+
this.testerConfig = merge(
|
329
|
+
{},
|
330
|
+
defaultConfig,
|
331
331
|
testerConfig,
|
332
332
|
{ rules: { "rule-tester/validate-ast": "error" } }
|
333
333
|
);
|
@@ -369,7 +369,7 @@ class RuleTester {
|
|
369
369
|
* @returns {void}
|
370
370
|
*/
|
371
371
|
static resetDefaultConfig() {
|
372
|
-
defaultConfig =
|
372
|
+
defaultConfig = merge({}, testerDefaultConfig);
|
373
373
|
}
|
374
374
|
|
375
375
|
|
@@ -465,7 +465,7 @@ class RuleTester {
|
|
465
465
|
* @private
|
466
466
|
*/
|
467
467
|
function runRuleForItem(item) {
|
468
|
-
let config =
|
468
|
+
let config = merge({}, testerConfig),
|
469
469
|
code, filename, output, beforeAST, afterAST;
|
470
470
|
|
471
471
|
if (typeof item === "string") {
|
@@ -477,13 +477,17 @@ class RuleTester {
|
|
477
477
|
* Assumes everything on the item is a config except for the
|
478
478
|
* parameters used by this tester
|
479
479
|
*/
|
480
|
-
const itemConfig =
|
480
|
+
const itemConfig = { ...item };
|
481
|
+
|
482
|
+
for (const parameter of RuleTesterParameters) {
|
483
|
+
delete itemConfig[parameter];
|
484
|
+
}
|
481
485
|
|
482
486
|
/*
|
483
487
|
* Create the config object from the tester config and this item
|
484
488
|
* specific configurations.
|
485
489
|
*/
|
486
|
-
config =
|
490
|
+
config = merge(
|
487
491
|
config,
|
488
492
|
itemConfig
|
489
493
|
);
|
@@ -589,7 +593,7 @@ class RuleTester {
|
|
589
593
|
* @private
|
590
594
|
*/
|
591
595
|
function assertASTDidntChange(beforeAST, afterAST) {
|
592
|
-
if (!
|
596
|
+
if (!equal(beforeAST, afterAST)) {
|
593
597
|
assert.fail("Rule should not modify AST.");
|
594
598
|
}
|
595
599
|
}
|
@@ -9,7 +9,6 @@
|
|
9
9
|
// Requirements
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
const lodash = require("lodash");
|
13
12
|
const astUtils = require("./utils/ast-utils");
|
14
13
|
|
15
14
|
//------------------------------------------------------------------------------
|
@@ -144,23 +143,33 @@ module.exports = {
|
|
144
143
|
* @returns {ASTNode|null} The last node or null.
|
145
144
|
*/
|
146
145
|
function getLastItem(node) {
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Returns the last element of an array
|
149
|
+
* @param {any[]} array The input array
|
150
|
+
* @returns {any} The last element
|
151
|
+
*/
|
152
|
+
function last(array) {
|
153
|
+
return array[array.length - 1];
|
154
|
+
}
|
155
|
+
|
147
156
|
switch (node.type) {
|
148
157
|
case "ObjectExpression":
|
149
158
|
case "ObjectPattern":
|
150
|
-
return
|
159
|
+
return last(node.properties);
|
151
160
|
case "ArrayExpression":
|
152
161
|
case "ArrayPattern":
|
153
|
-
return
|
162
|
+
return last(node.elements);
|
154
163
|
case "ImportDeclaration":
|
155
164
|
case "ExportNamedDeclaration":
|
156
|
-
return
|
165
|
+
return last(node.specifiers);
|
157
166
|
case "FunctionDeclaration":
|
158
167
|
case "FunctionExpression":
|
159
168
|
case "ArrowFunctionExpression":
|
160
|
-
return
|
169
|
+
return last(node.params);
|
161
170
|
case "CallExpression":
|
162
171
|
case "NewExpression":
|
163
|
-
return
|
172
|
+
return last(node.arguments);
|
164
173
|
default:
|
165
174
|
return null;
|
166
175
|
}
|
@@ -316,7 +325,7 @@ module.exports = {
|
|
316
325
|
"always-multiline": forceTrailingCommaIfMultiline,
|
317
326
|
"only-multiline": allowTrailingCommaIfMultiline,
|
318
327
|
never: forbidTrailingComma,
|
319
|
-
ignore:
|
328
|
+
ignore: () => {}
|
320
329
|
};
|
321
330
|
|
322
331
|
return {
|
@@ -181,7 +181,7 @@ module.exports = {
|
|
181
181
|
|
182
182
|
validateCommaItemSpacing({
|
183
183
|
comma: token,
|
184
|
-
left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.
|
184
|
+
left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.includes(token) ? null : previousToken,
|
185
185
|
right: astUtils.isCommaToken(nextToken) ? null : nextToken
|
186
186
|
}, token);
|
187
187
|
});
|
package/lib/rules/complexity.js
CHANGED
@@ -10,9 +10,8 @@
|
|
10
10
|
// Requirements
|
11
11
|
//------------------------------------------------------------------------------
|
12
12
|
|
13
|
-
const lodash = require("lodash");
|
14
|
-
|
15
13
|
const astUtils = require("./utils/ast-utils");
|
14
|
+
const { upperCaseFirst } = require("../shared/string-utils");
|
16
15
|
|
17
16
|
//------------------------------------------------------------------------------
|
18
17
|
// Rule Definition
|
@@ -95,7 +94,7 @@ module.exports = {
|
|
95
94
|
* @private
|
96
95
|
*/
|
97
96
|
function endFunction(node) {
|
98
|
-
const name =
|
97
|
+
const name = upperCaseFirst(astUtils.getFunctionNameWithKind(node));
|
99
98
|
const complexity = fns.pop();
|
100
99
|
|
101
100
|
if (complexity > THRESHOLD) {
|