eslint 7.11.0 → 7.12.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 +27 -0
- package/README.md +4 -3
- package/lib/cli-engine/cli-engine.js +26 -7
- package/lib/cli-engine/file-enumerator.js +7 -2
- package/lib/linter/report-translator.js +13 -9
- package/lib/rules/constructor-super.js +11 -0
- package/lib/rules/no-constant-condition.js +42 -20
- package/lib/rules/no-prototype-builtins.js +4 -4
- package/lib/rules/no-script-url.js +21 -7
- package/lib/rules/prefer-destructuring.js +19 -1
- package/lib/rules/prefer-template.js +14 -22
- package/lib/rules/quotes.js +5 -2
- package/lib/rules/space-before-blocks.js +34 -9
- package/lib/rules/utils/ast-utils.js +22 -7
- package/lib/rules/yoda.js +33 -23
- package/package.json +2 -2
- package/lib/cli-engine/cascading-config-array-factory.js +0 -502
- package/lib/cli-engine/config-array/config-array.js +0 -536
- package/lib/cli-engine/config-array/config-dependency.js +0 -128
- package/lib/cli-engine/config-array/extracted-config.js +0 -158
- package/lib/cli-engine/config-array/ignore-pattern.js +0 -249
- package/lib/cli-engine/config-array/index.js +0 -32
- package/lib/cli-engine/config-array/override-tester.js +0 -235
- package/lib/cli-engine/config-array-factory.js +0 -1092
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
v7.12.0 - October 23, 2020
|
2
|
+
|
3
|
+
* [`cbf3585`](https://github.com/eslint/eslint/commit/cbf3585f1d6c60414c07380367a8b4505ee3538d) Update: skip keyword check for fns in space-before-blocks (fixes #13553) (#13712) (Milos Djermanovic)
|
4
|
+
* [`256f656`](https://github.com/eslint/eslint/commit/256f656455b47bcf9ed3fc30fbf72532678f97da) Fix: autofix shouldn't produce template literals with `\8` or `\9` (#13737) (Milos Djermanovic)
|
5
|
+
* [`b165aa5`](https://github.com/eslint/eslint/commit/b165aa5f4d4d19328f13ab80e5f058cbce94c3a6) Fix: yoda rule autofix produces syntax errors with adjacent tokens (#13760) (Milos Djermanovic)
|
6
|
+
* [`3175316`](https://github.com/eslint/eslint/commit/3175316db26aebef4b19e269aca90c8ce3955363) Fix: prefer-destructuring invalid autofix with comma operator (#13761) (Milos Djermanovic)
|
7
|
+
* [`1a9f171`](https://github.com/eslint/eslint/commit/1a9f17151a4e93eb17c8a2bf4f0a5320cce616de) Chore: Remove more ESLintRC-related files (refs #13481) (#13762) (Nicholas C. Zakas)
|
8
|
+
* [`bfddced`](https://github.com/eslint/eslint/commit/bfddcedace5587d662c840c2edf33062b54a178e) Update: remove suggestion if it didn't provide a fix (fixes #13723) (#13772) (Milos Djermanovic)
|
9
|
+
* [`5183b14`](https://github.com/eslint/eslint/commit/5183b14a2420b42b4089fb134a61ae57142f31fd) Update: check template literal in no-script-url (#13775) (YeonJuan)
|
10
|
+
* [`bfe97d2`](https://github.com/eslint/eslint/commit/bfe97d2332e711ca76b1fd2e7f8548b0cc84cb1c) Sponsors: Sync README with website (ESLint Jenkins)
|
11
|
+
* [`6c51ade`](https://github.com/eslint/eslint/commit/6c51adeb86f1de292cd02d2ee19f7b56182e358b) Sponsors: Sync README with website (ESLint Jenkins)
|
12
|
+
* [`603de04`](https://github.com/eslint/eslint/commit/603de04cab5e700df12999af2918decd4da9d11b) Update: treat all literals like boolean literal in no-constant-condition (#13245) (Zen)
|
13
|
+
* [`289aa6f`](https://github.com/eslint/eslint/commit/289aa6fcef3874ba5f86455f9302dc4209ea83e5) Sponsors: Sync README with website (ESLint Jenkins)
|
14
|
+
* [`9a1f669`](https://github.com/eslint/eslint/commit/9a1f6694e59eb3e584d4c5a98b98675c895a9783) Sponsors: Sync README with website (ESLint Jenkins)
|
15
|
+
* [`637f818`](https://github.com/eslint/eslint/commit/637f8187404ded600fb3d4013b3cd495d5ae675b) Docs: add more examples for no-func-assign (fixes #13705) (#13777) (Nitin Kumar)
|
16
|
+
* [`17cc0dd`](https://github.com/eslint/eslint/commit/17cc0dd9b5d2d500359c36881cd3e5637443c133) Chore: add test case for no-func-assign (refs #13705) (#13783) (Nitin Kumar)
|
17
|
+
* [`dee0f77`](https://github.com/eslint/eslint/commit/dee0f7764a1d5a323c89b22c4db94acee2b3c718) Docs: add TOC to user-guide/configuring.md (#13727) (metasean)
|
18
|
+
* [`0510621`](https://github.com/eslint/eslint/commit/05106212985cb1ffa1e6fa996a57f6fd2fc3c970) Update: Fix && vs || short-circuiting false negatives (fixes #13634) (#13769) (Brandon Mills)
|
19
|
+
* [`8b6ed69`](https://github.com/eslint/eslint/commit/8b6ed691c48189b7d096339441a78cb5874d4137) Sponsors: Sync README with website (ESLint Jenkins)
|
20
|
+
* [`1457509`](https://github.com/eslint/eslint/commit/145750991b04fd4cfb3fff3c5d4211a4428e011c) Docs: fix broken links in Node.js API docs (#13771) (Laura Barluzzi)
|
21
|
+
* [`7c813d4`](https://github.com/eslint/eslint/commit/7c813d458f9aedf7a94351d137728a4647542879) Docs: Fix typo in v7 migration page (#13778) (Yusuke Sasaki)
|
22
|
+
* [`b025795`](https://github.com/eslint/eslint/commit/b0257953be704d0bb387fc15afd7859fd6f19ba5) Docs: Fix the format option name in the document (#13770) (Hideki Igarashi)
|
23
|
+
* [`84fd591`](https://github.com/eslint/eslint/commit/84fd591c234accc41bb5af555f178825012fd35d) Chore: Increase Mocha timeout for copying fixtures (#13768) (Brandon Mills)
|
24
|
+
* [`1faeb84`](https://github.com/eslint/eslint/commit/1faeb84e663d88c5d85a3cb3f15cd224cc552c2d) Docs: clarify that space-unary-ops doesn't apply when space is required (#13767) (Taylor Morgan)
|
25
|
+
* [`67c0605`](https://github.com/eslint/eslint/commit/67c06059dd1ddcee6f369c650ce71220da1510c3) Update: check computed keys in no-prototype-builtins (fixes #13088) (#13755) (Milos Djermanovic)
|
26
|
+
* [`b5e011c`](https://github.com/eslint/eslint/commit/b5e011c865e95d700d29cb9a4ba71c671d99e423) Sponsors: Sync README with website (ESLint Jenkins)
|
27
|
+
|
1
28
|
v7.11.0 - October 9, 2020
|
2
29
|
|
3
30
|
* [`23e966f`](https://github.com/eslint/eslint/commit/23e966f6cf2a6c6b699dff5d6950ece3cc396498) Chore: Refactor CLIEngine tests (refs #13481) (#13709) (Nicholas C. Zakas)
|
package/README.md
CHANGED
@@ -263,10 +263,11 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
263
263
|
|
264
264
|
<!-- NOTE: This section is autogenerated. Do not manually edit.-->
|
265
265
|
<!--sponsorsstart-->
|
266
|
-
<h3>
|
267
|
-
<p><a href="https://
|
266
|
+
<h3>Platinum Sponsors</h3>
|
267
|
+
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/ff91f0b/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
|
268
|
+
<p><a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/e780cd4/logo.png" alt="Shopify" 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://aka.ms/microsoftfossfund"><img src="https://avatars1.githubusercontent.com/u/67931232?u=7fddc652a464d7151b97e8f108392af7d54fa3e8&v=4" alt="Microsoft FOSS Fund Sponsorships" height="96"></a></p><h3>Silver Sponsors</h3>
|
268
269
|
<p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/amp/c8a3b25/logo.png" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
|
269
|
-
<p><a href="https://writersperhour.com/write-my-essay"><img src="https://images.opencollective.com/writersperhour/5787d4b/logo.png" alt="Writers Per Hour" height="32"></a> <a href="https://www.betacalendars.com/printable-calendar"><img src="https://images.opencollective.com/betacalendars/9334b33/logo.png" alt="2021 calendar" height="32"></a> <a href="https://buy.fineproxy.org/eng/"><img src="https://images.opencollective.com/buy-fineproxy-org/2002c40/logo.png" alt="Buy.Fineproxy.Org" height="32"></a> <a href="https://www.veikkaajat.com"><img src="https://images.opencollective.com/veikkaajat/b92b427/logo.png" alt="Veikkaajat.com" height="32"></a> <a href="https://www.
|
270
|
+
<p><a href="https://writersperhour.com/write-my-essay"><img src="https://images.opencollective.com/writersperhour/5787d4b/logo.png" alt="Writers Per Hour" height="32"></a> <a href="https://www.betacalendars.com/printable-calendar"><img src="https://images.opencollective.com/betacalendars/9334b33/logo.png" alt="2021 calendar" height="32"></a> <a href="https://buy.fineproxy.org/eng/"><img src="https://images.opencollective.com/buy-fineproxy-org/2002c40/logo.png" alt="Buy.Fineproxy.Org" height="32"></a> <a href="https://www.veikkaajat.com"><img src="https://images.opencollective.com/veikkaajat/b92b427/logo.png" alt="Veikkaajat.com" height="32"></a> <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://discordapp.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.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" 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>
|
270
271
|
<!--sponsorsend-->
|
271
272
|
|
272
273
|
## <a name="technology-sponsors"></a>Technology Sponsors
|
@@ -19,14 +19,29 @@ const fs = require("fs");
|
|
19
19
|
const path = require("path");
|
20
20
|
const defaultOptions = require("../../conf/default-cli-options");
|
21
21
|
const pkg = require("../../package.json");
|
22
|
-
|
23
|
-
|
24
|
-
const
|
22
|
+
|
23
|
+
|
24
|
+
const {
|
25
|
+
Legacy: {
|
26
|
+
ConfigOps,
|
27
|
+
naming,
|
28
|
+
CascadingConfigArrayFactory,
|
29
|
+
IgnorePattern,
|
30
|
+
getUsedExtractedConfigs
|
31
|
+
}
|
32
|
+
} = require("@eslint/eslintrc");
|
33
|
+
|
34
|
+
/*
|
35
|
+
* For some reason, ModuleResolver must be included via filepath instead of by
|
36
|
+
* API exports in order to work properly. That's why this is separated out onto
|
37
|
+
* its own require() statement.
|
38
|
+
*/
|
39
|
+
const ModuleResolver = require("@eslint/eslintrc/lib/shared/relative-module-resolver");
|
40
|
+
const { FileEnumerator } = require("./file-enumerator");
|
41
|
+
|
25
42
|
const { Linter } = require("../linter");
|
26
43
|
const builtInRules = require("../rules");
|
27
|
-
const
|
28
|
-
const { IgnorePattern, getUsedExtractedConfigs } = require("./config-array");
|
29
|
-
const { FileEnumerator } = require("./file-enumerator");
|
44
|
+
const loadRules = require("./load-rules");
|
30
45
|
const hash = require("./hash");
|
31
46
|
const LintResultCache = require("./lint-result-cache");
|
32
47
|
|
@@ -559,7 +574,11 @@ class CLIEngine {
|
|
559
574
|
resolvePluginsRelativeTo: options.resolvePluginsRelativeTo,
|
560
575
|
rulePaths: options.rulePaths,
|
561
576
|
specificConfigPath: options.configFile,
|
562
|
-
useEslintrc: options.useEslintrc
|
577
|
+
useEslintrc: options.useEslintrc,
|
578
|
+
builtInRules,
|
579
|
+
loadRules,
|
580
|
+
eslintRecommendedPath: path.resolve(__dirname, "../../conf/eslint-recommended.js"),
|
581
|
+
eslintAllPath: path.resolve(__dirname, "../../conf/eslint-all.js")
|
563
582
|
});
|
564
583
|
const fileEnumerator = new FileEnumerator({
|
565
584
|
configArrayFactory,
|
@@ -40,8 +40,13 @@ const getGlobParent = require("glob-parent");
|
|
40
40
|
const isGlob = require("is-glob");
|
41
41
|
const { escapeRegExp } = require("lodash");
|
42
42
|
const { Minimatch } = require("minimatch");
|
43
|
-
|
44
|
-
const {
|
43
|
+
|
44
|
+
const {
|
45
|
+
Legacy: {
|
46
|
+
IgnorePattern,
|
47
|
+
CascadingConfigArrayFactory
|
48
|
+
}
|
49
|
+
} = require("@eslint/eslintrc");
|
45
50
|
const debug = require("debug")("eslint:file-enumerator");
|
46
51
|
|
47
52
|
//------------------------------------------------------------------------------
|
@@ -196,15 +196,19 @@ function mapSuggestions(descriptor, sourceCode, messages) {
|
|
196
196
|
return [];
|
197
197
|
}
|
198
198
|
|
199
|
-
return descriptor.suggest
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
199
|
+
return descriptor.suggest
|
200
|
+
.map(suggestInfo => {
|
201
|
+
const computedDesc = suggestInfo.desc || messages[suggestInfo.messageId];
|
202
|
+
|
203
|
+
return {
|
204
|
+
...suggestInfo,
|
205
|
+
desc: interpolate(computedDesc, suggestInfo.data),
|
206
|
+
fix: normalizeFixes(suggestInfo, sourceCode)
|
207
|
+
};
|
208
|
+
})
|
209
|
+
|
210
|
+
// Remove suggestions that didn't provide a fix
|
211
|
+
.filter(({ fix }) => fix);
|
208
212
|
}
|
209
213
|
|
210
214
|
/**
|
@@ -79,6 +79,17 @@ function isPossibleConstructor(node) {
|
|
79
79
|
return false;
|
80
80
|
|
81
81
|
case "LogicalExpression":
|
82
|
+
|
83
|
+
/*
|
84
|
+
* If the && operator short-circuits, the left side was falsy and therefore not a constructor, and if
|
85
|
+
* it doesn't short-circuit, it takes the value from the right side, so the right side must always be a
|
86
|
+
* possible constructor. A future improvement could verify that the left side could be truthy by
|
87
|
+
* excluding falsy literals.
|
88
|
+
*/
|
89
|
+
if (node.operator === "&&") {
|
90
|
+
return isPossibleConstructor(node.right);
|
91
|
+
}
|
92
|
+
|
82
93
|
return (
|
83
94
|
isPossibleConstructor(node.left) ||
|
84
95
|
isPossibleConstructor(node.right)
|
@@ -9,9 +9,6 @@
|
|
9
9
|
// Helpers
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
const EQUALITY_OPERATORS = ["===", "!==", "==", "!="];
|
13
|
-
const RELATIONAL_OPERATORS = [">", "<", ">=", "<=", "in", "instanceof"];
|
14
|
-
|
15
12
|
//------------------------------------------------------------------------------
|
16
13
|
// Rule Definition
|
17
14
|
//------------------------------------------------------------------------------
|
@@ -56,6 +53,35 @@ module.exports = {
|
|
56
53
|
// Helpers
|
57
54
|
//--------------------------------------------------------------------------
|
58
55
|
|
56
|
+
/**
|
57
|
+
* Returns literal's value converted to the Boolean type
|
58
|
+
* @param {ASTNode} node any `Literal` node
|
59
|
+
* @returns {boolean | null} `true` when node is truthy, `false` when node is falsy,
|
60
|
+
* `null` when it cannot be determined.
|
61
|
+
*/
|
62
|
+
function getBooleanValue(node) {
|
63
|
+
if (node.value === null) {
|
64
|
+
|
65
|
+
/*
|
66
|
+
* it might be a null literal or bigint/regex literal in unsupported environments .
|
67
|
+
* https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es5.md#regexpliteral
|
68
|
+
* https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es2020.md#bigintliteral
|
69
|
+
*/
|
70
|
+
|
71
|
+
if (node.raw === "null") {
|
72
|
+
return false;
|
73
|
+
}
|
74
|
+
|
75
|
+
// regex is always truthy
|
76
|
+
if (typeof node.regex === "object") {
|
77
|
+
return true;
|
78
|
+
}
|
79
|
+
|
80
|
+
return null;
|
81
|
+
}
|
82
|
+
|
83
|
+
return !!node.value;
|
84
|
+
}
|
59
85
|
|
60
86
|
/**
|
61
87
|
* Checks if a branch node of LogicalExpression short circuits the whole condition
|
@@ -66,15 +92,23 @@ module.exports = {
|
|
66
92
|
function isLogicalIdentity(node, operator) {
|
67
93
|
switch (node.type) {
|
68
94
|
case "Literal":
|
69
|
-
return (operator === "||" && node
|
70
|
-
(operator === "&&" && node
|
95
|
+
return (operator === "||" && getBooleanValue(node) === true) ||
|
96
|
+
(operator === "&&" && getBooleanValue(node) === false);
|
71
97
|
|
72
98
|
case "UnaryExpression":
|
73
99
|
return (operator === "&&" && node.operator === "void");
|
74
100
|
|
75
101
|
case "LogicalExpression":
|
76
|
-
|
77
|
-
|
102
|
+
|
103
|
+
/*
|
104
|
+
* handles `a && false || b`
|
105
|
+
* `false` is an identity element of `&&` but not `||`
|
106
|
+
*/
|
107
|
+
return operator === node.operator &&
|
108
|
+
(
|
109
|
+
isLogicalIdentity(node.left, node.operator) ||
|
110
|
+
isLogicalIdentity(node.right, node.operator)
|
111
|
+
);
|
78
112
|
|
79
113
|
// no default
|
80
114
|
}
|
@@ -129,21 +163,9 @@ module.exports = {
|
|
129
163
|
const isLeftConstant = isConstant(node.left, inBooleanPosition);
|
130
164
|
const isRightConstant = isConstant(node.right, inBooleanPosition);
|
131
165
|
const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator));
|
132
|
-
const isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator));
|
166
|
+
const isRightShortCircuit = (inBooleanPosition && isRightConstant && isLogicalIdentity(node.right, node.operator));
|
133
167
|
|
134
168
|
return (isLeftConstant && isRightConstant) ||
|
135
|
-
(
|
136
|
-
|
137
|
-
// in the case of an "OR", we need to know if the right constant value is truthy
|
138
|
-
node.operator === "||" &&
|
139
|
-
isRightConstant &&
|
140
|
-
node.right.value &&
|
141
|
-
(
|
142
|
-
!node.parent ||
|
143
|
-
node.parent.type !== "BinaryExpression" ||
|
144
|
-
!(EQUALITY_OPERATORS.includes(node.parent.operator) || RELATIONAL_OPERATORS.includes(node.parent.operator))
|
145
|
-
)
|
146
|
-
) ||
|
147
169
|
isLeftShortCircuit ||
|
148
170
|
isRightShortCircuit;
|
149
171
|
}
|
@@ -46,15 +46,15 @@ module.exports = {
|
|
46
46
|
*/
|
47
47
|
function disallowBuiltIns(node) {
|
48
48
|
|
49
|
-
// TODO: just use `astUtils.getStaticPropertyName(node.callee)`
|
50
49
|
const callee = astUtils.skipChainExpression(node.callee);
|
51
50
|
|
52
|
-
if (callee.type !== "MemberExpression"
|
51
|
+
if (callee.type !== "MemberExpression") {
|
53
52
|
return;
|
54
53
|
}
|
55
|
-
const propName = callee.property.name;
|
56
54
|
|
57
|
-
|
55
|
+
const propName = astUtils.getStaticPropertyName(callee);
|
56
|
+
|
57
|
+
if (propName !== null && DISALLOWED_PROPS.indexOf(propName) > -1) {
|
58
58
|
context.report({
|
59
59
|
messageId: "prototypeBuildIn",
|
60
60
|
loc: callee.property.loc,
|
@@ -7,6 +7,8 @@
|
|
7
7
|
|
8
8
|
"use strict";
|
9
9
|
|
10
|
+
const astUtils = require("./utils/ast-utils");
|
11
|
+
|
10
12
|
//------------------------------------------------------------------------------
|
11
13
|
// Rule Definition
|
12
14
|
//------------------------------------------------------------------------------
|
@@ -31,18 +33,30 @@ module.exports = {
|
|
31
33
|
|
32
34
|
create(context) {
|
33
35
|
|
36
|
+
/**
|
37
|
+
* Check whether a node's static value starts with "javascript:" or not.
|
38
|
+
* And report an error for unexpected script URL.
|
39
|
+
* @param {ASTNode} node node to check
|
40
|
+
* @returns {void}
|
41
|
+
*/
|
42
|
+
function check(node) {
|
43
|
+
const value = astUtils.getStaticStringValue(node);
|
44
|
+
|
45
|
+
if (typeof value === "string" && value.toLowerCase().indexOf("javascript:") === 0) {
|
46
|
+
context.report({ node, messageId: "unexpectedScriptURL" });
|
47
|
+
}
|
48
|
+
}
|
34
49
|
return {
|
35
|
-
|
36
50
|
Literal(node) {
|
37
51
|
if (node.value && typeof node.value === "string") {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
52
|
+
check(node);
|
53
|
+
}
|
54
|
+
},
|
55
|
+
TemplateLiteral(node) {
|
56
|
+
if (!(node.parent && node.parent.type === "TaggedTemplateExpression")) {
|
57
|
+
check(node);
|
43
58
|
}
|
44
59
|
}
|
45
60
|
};
|
46
|
-
|
47
61
|
}
|
48
62
|
};
|
@@ -4,6 +4,18 @@
|
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Requirements
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const astUtils = require("./utils/ast-utils");
|
12
|
+
|
13
|
+
//------------------------------------------------------------------------------
|
14
|
+
// Helpers
|
15
|
+
//------------------------------------------------------------------------------
|
16
|
+
|
17
|
+
const PRECEDENCE_OF_ASSIGNMENT_EXPR = astUtils.getPrecedence({ type: "AssignmentExpression" });
|
18
|
+
|
7
19
|
//------------------------------------------------------------------------------
|
8
20
|
// Rule Definition
|
9
21
|
//------------------------------------------------------------------------------
|
@@ -185,9 +197,15 @@ module.exports = {
|
|
185
197
|
return null;
|
186
198
|
}
|
187
199
|
|
200
|
+
let objectText = sourceCode.getText(rightNode.object);
|
201
|
+
|
202
|
+
if (astUtils.getPrecedence(rightNode.object) < PRECEDENCE_OF_ASSIGNMENT_EXPR) {
|
203
|
+
objectText = `(${objectText})`;
|
204
|
+
}
|
205
|
+
|
188
206
|
return fixer.replaceText(
|
189
207
|
node,
|
190
|
-
`{${rightNode.property.name}} = ${
|
208
|
+
`{${rightNode.property.name}} = ${objectText}`
|
191
209
|
);
|
192
210
|
}
|
193
211
|
|
@@ -39,33 +39,25 @@ function getTopConcatBinaryExpression(node) {
|
|
39
39
|
}
|
40
40
|
|
41
41
|
/**
|
42
|
-
*
|
42
|
+
* Checks whether or not a node contains a string literal with an octal or non-octal decimal escape sequence
|
43
43
|
* @param {ASTNode} node A node to check
|
44
|
-
* @returns {boolean} `true` if
|
44
|
+
* @returns {boolean} `true` if at least one string literal within the node contains
|
45
|
+
* an octal or non-octal decimal escape sequence
|
45
46
|
*/
|
46
|
-
function
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
return false;
|
47
|
+
function hasOctalOrNonOctalDecimalEscapeSequence(node) {
|
48
|
+
if (isConcatenation(node)) {
|
49
|
+
return (
|
50
|
+
hasOctalOrNonOctalDecimalEscapeSequence(node.left) ||
|
51
|
+
hasOctalOrNonOctalDecimalEscapeSequence(node.right)
|
52
|
+
);
|
53
53
|
}
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
/**
|
59
|
-
* Checks whether or not a node contains a octal escape sequence
|
60
|
-
* @param {ASTNode} node A node to check
|
61
|
-
* @returns {boolean} `true` if the node contains an octal escape sequence
|
62
|
-
*/
|
63
|
-
function hasOctalEscapeSequence(node) {
|
64
|
-
if (isConcatenation(node)) {
|
65
|
-
return hasOctalEscapeSequence(node.left) || hasOctalEscapeSequence(node.right);
|
55
|
+
// No need to check TemplateLiterals – would throw parsing error
|
56
|
+
if (node.type === "Literal" && typeof node.value === "string") {
|
57
|
+
return astUtils.hasOctalOrNonOctalDecimalEscapeSequence(node.raw);
|
66
58
|
}
|
67
59
|
|
68
|
-
return
|
60
|
+
return false;
|
69
61
|
}
|
70
62
|
|
71
63
|
/**
|
@@ -237,7 +229,7 @@ module.exports = {
|
|
237
229
|
function fixNonStringBinaryExpression(fixer, node) {
|
238
230
|
const topBinaryExpr = getTopConcatBinaryExpression(node.parent);
|
239
231
|
|
240
|
-
if (
|
232
|
+
if (hasOctalOrNonOctalDecimalEscapeSequence(topBinaryExpr)) {
|
241
233
|
return null;
|
242
234
|
}
|
243
235
|
|
package/lib/rules/quotes.js
CHANGED
@@ -282,9 +282,12 @@ module.exports = {
|
|
282
282
|
description: settings.description
|
283
283
|
},
|
284
284
|
fix(fixer) {
|
285
|
-
if (quoteOption === "backtick" && astUtils.
|
285
|
+
if (quoteOption === "backtick" && astUtils.hasOctalOrNonOctalDecimalEscapeSequence(rawVal)) {
|
286
286
|
|
287
|
-
|
287
|
+
/*
|
288
|
+
* An octal or non-octal decimal escape sequence in a template literal would
|
289
|
+
* produce syntax error, even in non-strict mode.
|
290
|
+
*/
|
288
291
|
return null;
|
289
292
|
}
|
290
293
|
|
@@ -5,8 +5,31 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
8
12
|
const astUtils = require("./utils/ast-utils");
|
9
13
|
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Helpers
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Checks whether the given node represents the body of a function.
|
20
|
+
* @param {ASTNode} node the node to check.
|
21
|
+
* @returns {boolean} `true` if the node is function body.
|
22
|
+
*/
|
23
|
+
function isFunctionBody(node) {
|
24
|
+
const parent = node.parent;
|
25
|
+
|
26
|
+
return (
|
27
|
+
node.type === "BlockStatement" &&
|
28
|
+
astUtils.isFunction(parent) &&
|
29
|
+
parent.body === node
|
30
|
+
);
|
31
|
+
}
|
32
|
+
|
10
33
|
//------------------------------------------------------------------------------
|
11
34
|
// Rule Definition
|
12
35
|
//------------------------------------------------------------------------------
|
@@ -82,13 +105,16 @@ module.exports = {
|
|
82
105
|
}
|
83
106
|
|
84
107
|
/**
|
85
|
-
* Checks whether
|
86
|
-
*
|
87
|
-
*
|
88
|
-
* @
|
108
|
+
* Checks whether the spacing before the given block is already controlled by another rule:
|
109
|
+
* - `arrow-spacing` checks spaces after `=>`.
|
110
|
+
* - `keyword-spacing` checks spaces after keywords in certain contexts.
|
111
|
+
* @param {Token} precedingToken first token before the block.
|
112
|
+
* @param {ASTNode|Token} node `BlockStatement` node or `{` token of a `SwitchStatement` node.
|
113
|
+
* @returns {boolean} `true` if requiring or disallowing spaces before the given block could produce conflicts with other rules.
|
89
114
|
*/
|
90
|
-
function isConflicted(
|
91
|
-
return (
|
115
|
+
function isConflicted(precedingToken, node) {
|
116
|
+
return astUtils.isArrowToken(precedingToken) ||
|
117
|
+
astUtils.isKeywordToken(precedingToken) && !isFunctionBody(node);
|
92
118
|
}
|
93
119
|
|
94
120
|
/**
|
@@ -99,13 +125,12 @@ module.exports = {
|
|
99
125
|
function checkPrecedingSpace(node) {
|
100
126
|
const precedingToken = sourceCode.getTokenBefore(node);
|
101
127
|
|
102
|
-
if (precedingToken && !isConflicted(precedingToken) && astUtils.isTokenOnSameLine(precedingToken, node)) {
|
128
|
+
if (precedingToken && !isConflicted(precedingToken, node) && astUtils.isTokenOnSameLine(precedingToken, node)) {
|
103
129
|
const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
|
104
|
-
const parent = context.getAncestors().pop();
|
105
130
|
let requireSpace;
|
106
131
|
let requireNoSpace;
|
107
132
|
|
108
|
-
if (
|
133
|
+
if (isFunctionBody(node)) {
|
109
134
|
requireSpace = alwaysFunctions;
|
110
135
|
requireNoSpace = neverFunctions;
|
111
136
|
} else if (node.type === "ClassBody") {
|
@@ -38,7 +38,9 @@ const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
|
|
38
38
|
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
|
39
39
|
|
40
40
|
const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
|
41
|
-
|
41
|
+
|
42
|
+
// Tests the presence of at least one LegacyOctalEscapeSequence or NonOctalDecimalEscapeSequence in a raw string
|
43
|
+
const OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN = /^(?:[^\\]|\\.)*\\(?:[1-9]|0[0-9])/su;
|
42
44
|
|
43
45
|
const LOGICAL_ASSIGNMENT_OPERATORS = new Set(["&&=", "||=", "??="]);
|
44
46
|
|
@@ -1611,6 +1613,17 @@ module.exports = {
|
|
1611
1613
|
}
|
1612
1614
|
|
1613
1615
|
case "LogicalExpression":
|
1616
|
+
|
1617
|
+
/*
|
1618
|
+
* If the && operator short-circuits, the left side was falsy and therefore not an error, and if it
|
1619
|
+
* doesn't short-circuit, it takes the value from the right side, so the right side must always be
|
1620
|
+
* a plausible error. A future improvement could verify that the left side could be truthy by
|
1621
|
+
* excluding falsy literals.
|
1622
|
+
*/
|
1623
|
+
if (node.operator === "&&") {
|
1624
|
+
return module.exports.couldBeError(node.right);
|
1625
|
+
}
|
1626
|
+
|
1614
1627
|
return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right);
|
1615
1628
|
|
1616
1629
|
case "ConditionalExpression":
|
@@ -1766,17 +1779,19 @@ module.exports = {
|
|
1766
1779
|
},
|
1767
1780
|
|
1768
1781
|
/**
|
1769
|
-
* Determines whether the given raw string contains an octal escape sequence
|
1782
|
+
* Determines whether the given raw string contains an octal escape sequence
|
1783
|
+
* or a non-octal decimal escape sequence ("\8", "\9").
|
1770
1784
|
*
|
1771
|
-
* "\1", "\2" ... "\7"
|
1772
|
-
* "\00", "\01" ... "\09"
|
1785
|
+
* "\1", "\2" ... "\7", "\8", "\9"
|
1786
|
+
* "\00", "\01" ... "\07", "\08", "\09"
|
1773
1787
|
*
|
1774
1788
|
* "\0", when not followed by a digit, is not an octal escape sequence.
|
1775
1789
|
* @param {string} rawString A string in its raw representation.
|
1776
|
-
* @returns {boolean} `true` if the string contains at least one octal escape sequence
|
1790
|
+
* @returns {boolean} `true` if the string contains at least one octal escape sequence
|
1791
|
+
* or at least one non-octal decimal escape sequence.
|
1777
1792
|
*/
|
1778
|
-
|
1779
|
-
return
|
1793
|
+
hasOctalOrNonOctalDecimalEscapeSequence(rawString) {
|
1794
|
+
return OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN.test(rawString);
|
1780
1795
|
},
|
1781
1796
|
|
1782
1797
|
isLogicalExpression,
|