eslint 7.13.0 → 7.17.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 +50 -0
- package/README.md +2 -7
- package/bin/eslint.js +1 -1
- package/lib/eslint/eslint.js +2 -2
- package/lib/rules/arrow-body-style.js +1 -1
- package/lib/rules/callback-return.js +2 -2
- package/lib/rules/dot-location.js +1 -1
- package/lib/rules/func-call-spacing.js +2 -2
- package/lib/rules/index.js +2 -0
- package/lib/rules/multiline-ternary.js +63 -6
- package/lib/rules/no-constant-condition.js +25 -6
- package/lib/rules/no-control-regex.js +0 -1
- package/lib/rules/no-extend-native.js +1 -1
- package/lib/rules/no-extra-parens.js +26 -12
- package/lib/rules/no-import-assign.js +4 -4
- package/lib/rules/no-invalid-regexp.js +1 -1
- package/lib/rules/no-irregular-whitespace.js +7 -9
- package/lib/rules/no-nonoctal-decimal-escape.js +147 -0
- package/lib/rules/no-restricted-exports.js +1 -1
- package/lib/rules/no-this-before-super.js +1 -1
- package/lib/rules/no-unsafe-optional-chaining.js +205 -0
- package/lib/rules/no-useless-constructor.js +8 -0
- package/lib/rules/no-useless-escape.js +4 -4
- package/lib/rules/one-var.js +35 -7
- package/lib/rules/prefer-destructuring.js +2 -2
- package/lib/rules/prefer-exponentiation-operator.js +1 -0
- package/lib/rules/prefer-reflect.js +2 -2
- package/lib/rules/require-atomic-updates.js +3 -0
- package/lib/rules/space-unary-ops.js +1 -1
- package/lib/rules/utils/ast-utils.js +2 -2
- package/lib/shared/deprecation-warnings.js +1 -1
- package/lib/shared/types.js +2 -2
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,53 @@
|
|
1
|
+
v7.17.0 - January 1, 2021
|
2
|
+
|
3
|
+
* [`e128e77`](https://github.com/eslint/eslint/commit/e128e775e9fa116a0ad68a071f1f0997589f8cd4) Update: check logical assignment in no-constant-condition (#13946) (Milos Djermanovic)
|
4
|
+
* [`cc48713`](https://github.com/eslint/eslint/commit/cc4871369645c3409dc56ded7a555af8a9f63d51) Chore: refactor calculating range and loc in no-useless-escape (#13964) (Milos Djermanovic)
|
5
|
+
* [`535fe47`](https://github.com/eslint/eslint/commit/535fe47fee6544b4957378f9408117c8318d4762) Update: use regexpp's default ecmaVersion in no-control-regex (#13969) (Milos Djermanovic)
|
6
|
+
* [`83e98cd`](https://github.com/eslint/eslint/commit/83e98cd48ce3d1acf729f4fb9be40cff332abd6e) Fix: use regexpp's default ecmaVersion in no-invalid-regexp (#13968) (Milos Djermanovic)
|
7
|
+
* [`7297363`](https://github.com/eslint/eslint/commit/7297363ea355d0e3b2a74aaec586126deb91fd93) Docs: fix examples for no-multi-str (#13966) (Milos Djermanovic)
|
8
|
+
* [`0649871`](https://github.com/eslint/eslint/commit/06498716bfba65ed8c7217917a29a07ad267193a) Update: add autofix to rule multiline-ternary (#13958) (薛定谔的猫)
|
9
|
+
* [`f6e7e32`](https://github.com/eslint/eslint/commit/f6e7e3231bc43c989f8c953de8e0d328bac5eea0) Fix: no-useless-escape wrong loc and fix with CRLF in template elements (#13953) (Milos Djermanovic)
|
10
|
+
* [`19c69c0`](https://github.com/eslint/eslint/commit/19c69c0293a98634ff0d4884a0cdabc1213ebcb4) Fix: one-var shouldn't split declaration if it isn't in a statement list (#13959) (Milos Djermanovic)
|
11
|
+
* [`e451b96`](https://github.com/eslint/eslint/commit/e451b9664aface32ad9321eaf5619c875dc76553) Docs: update build tool for webpack (#13962) (Sam Chen)
|
12
|
+
* [`c3e9acc`](https://github.com/eslint/eslint/commit/c3e9accce2f61b04ab699fd37c90703305281aa3) Chore: fix typos (#13960) (YeonJuan)
|
13
|
+
* [`7289ecf`](https://github.com/eslint/eslint/commit/7289ecf58ed0d2e7f0ad7f1e5004c8927a7bf805) Sponsors: Sync README with website (ESLint Jenkins)
|
14
|
+
|
15
|
+
v7.16.0 - December 18, 2020
|
16
|
+
|
17
|
+
* [`a62ad6f`](https://github.com/eslint/eslint/commit/a62ad6f03151358b93b5fede022a30d67310705c) Update: fix false negative of no-extra-parens with NewExpression (#13930) (Milos Djermanovic)
|
18
|
+
* [`f85b4c7`](https://github.com/eslint/eslint/commit/f85b4c72668c95c79fdb342b74dbd53d21baa93f) Fix: require-atomic-updates false positive across await (fixes #11954) (#13915) (buhi)
|
19
|
+
* [`301d0c0`](https://github.com/eslint/eslint/commit/301d0c05229dbd6cfb1045d716524e8ec46fa2c1) Fix: no-constant-condition false positives with unary expressions (#13927) (Milos Djermanovic)
|
20
|
+
* [`555c128`](https://github.com/eslint/eslint/commit/555c128b49ae6d9c100a9f8429416417edb40d13) Fix: false positive with await and ** in no-extra-parens (fixes #12739) (#13923) (Milos Djermanovic)
|
21
|
+
* [`d93c935`](https://github.com/eslint/eslint/commit/d93c9350361d2aa1a1976c553e47ab399e51e8c9) Docs: update JSON Schema links (#13936) (Milos Djermanovic)
|
22
|
+
* [`8d0c93a`](https://github.com/eslint/eslint/commit/8d0c93a7ef9449c7b7d082bbb4b7d8465b0d6bac) Upgrade: table@6.0.4 (#13920) (Rouven Weßling)
|
23
|
+
* [`9247683`](https://github.com/eslint/eslint/commit/924768377a4935a95a6ff3866f9545a5a6178b53) Docs: Remove for deleted npm run profile script (#13931) (Brandon Mills)
|
24
|
+
* [`ab240d4`](https://github.com/eslint/eslint/commit/ab240d49833b4e6e594667c1abe5b0caa8a9cf70) Fix: prefer-exponentiation-operator invalid autofix with await (#13924) (Milos Djermanovic)
|
25
|
+
* [`dc76911`](https://github.com/eslint/eslint/commit/dc7691103554a99bdb2142561cb507f50f547e3b) Chore: Add .pre-commit-hooks.yaml file (#13628) (Álvaro Mondéjar)
|
26
|
+
* [`2124e1b`](https://github.com/eslint/eslint/commit/2124e1b5dad30a905dc26bde9da472bf622d3f50) Docs: Fix wrong rule name (#13913) (noisyboy25)
|
27
|
+
* [`06b5809`](https://github.com/eslint/eslint/commit/06b58096975935ec016d96dd5f333f059c270f26) Sponsors: Sync README with website (ESLint Jenkins)
|
28
|
+
* [`26fc12f`](https://github.com/eslint/eslint/commit/26fc12f88109af9d4081bf0e16364c411bce3009) Docs: Update README team and sponsors (ESLint Jenkins)
|
29
|
+
|
30
|
+
v7.15.0 - December 5, 2020
|
31
|
+
|
32
|
+
* [`5c11aab`](https://github.com/eslint/eslint/commit/5c11aabbe8249aeb8cad29bc6a33fc20c8c683ef) Upgrade: @eslint/esintrc and espree for bug fixes (refs #13878) (#13908) (Brandon Mills)
|
33
|
+
* [`0eb7957`](https://github.com/eslint/eslint/commit/0eb7957e27fd521317bd5c8479ce7abc1399169c) Upgrade: file-entry-cache@6.0.0 (#13877) (Rouven Weßling)
|
34
|
+
* [`683ad00`](https://github.com/eslint/eslint/commit/683ad00c41e1ae4d889deff82b2a94318e8c2129) New: no-unsafe-optional-chaining rule (fixes #13431) (#13859) (YeonJuan)
|
35
|
+
* [`cbc57fb`](https://github.com/eslint/eslint/commit/cbc57fb7d07c00663ed5781f5e6bc8f534cc2d76) Fix: one-var autofixing for export (fixes #13834) (#13891) (Anix)
|
36
|
+
* [`110cf96`](https://github.com/eslint/eslint/commit/110cf962d05625a8a1bf7b5f4ec2194db150eb32) Docs: Fix a broken link in working-with-rules.md (#13875) (Anton Niklasson)
|
37
|
+
|
38
|
+
v7.14.0 - November 20, 2020
|
39
|
+
|
40
|
+
* [`5f09073`](https://github.com/eslint/eslint/commit/5f0907399a9666dec78c74384c8969c01483c30e) Update: fix 'skip' options in no-irregular-whitespace (fixes #13852) (#13853) (Milos Djermanovic)
|
41
|
+
* [`1861b40`](https://github.com/eslint/eslint/commit/1861b4086f1018f43ab19744d866d5da986c500d) Docs: correct the function-call-argument-newline 'default' descriptions (#13866) (Trevin Hofmann)
|
42
|
+
* [`98c00c4`](https://github.com/eslint/eslint/commit/98c00c41d2aecb3a990393d430694f4ce6b47de5) New: Add no-nonoctal-decimal-escape rule (fixes #13765) (#13845) (Milos Djermanovic)
|
43
|
+
* [`95d2fe6`](https://github.com/eslint/eslint/commit/95d2fe6057498fc1cc2193d28c8c2d1593224b33) Chore: remove eslint comment from no-octal-escape tests (#13846) (Milos Djermanovic)
|
44
|
+
* [`2004b7e`](https://github.com/eslint/eslint/commit/2004b7ecd3db0d4e7376cc3344246f7b9ada5801) Fix: enable debug logs for @eslint/eslintrc (fixes #13850) (#13861) (Milos Djermanovic)
|
45
|
+
* [`d2239a1`](https://github.com/eslint/eslint/commit/d2239a1fdec452e24ede04e990d16d42516fa538) Fix: no-useless-constructor crash on bodyless constructor (fixes #13830) (#13842) (Ari Perkkiö)
|
46
|
+
* [`eda0aa1`](https://github.com/eslint/eslint/commit/eda0aa18498dd85eb618873e8e0f4ac97032cfca) Docs: no-restricted-imports is only for static imports (#13863) (Robat Williams)
|
47
|
+
* [`042ae44`](https://github.com/eslint/eslint/commit/042ae44682a8a6c5037d920689124e2304056dd8) Docs: Fix JS syntax and doc URL in working-with-custom-formatters.md (#13828) (Raphael LANG)
|
48
|
+
* [`038dc73`](https://github.com/eslint/eslint/commit/038dc73c99ae68eae2035ef303f3a947053c8f05) Chore: Test on Node.js 15 (#13844) (Brandon Mills)
|
49
|
+
* [`37a06d6`](https://github.com/eslint/eslint/commit/37a06d633d3669f0f43236141dc43465b8bc7ec5) Sponsors: Sync README with website (ESLint Jenkins)
|
50
|
+
|
1
51
|
v7.13.0 - November 6, 2020
|
2
52
|
|
3
53
|
* [`254e00f`](https://github.com/eslint/eslint/commit/254e00fea8745ff5a8bcc8cb874fcfd02996d81b) New: Configurable List Size For Per-Rule Performance Metrics (#13812) (Bryan Mishkin)
|
package/README.md
CHANGED
@@ -207,11 +207,6 @@ Brandon Mills
|
|
207
207
|
Toru Nagashima
|
208
208
|
</a>
|
209
209
|
</td><td align="center" valign="top" width="11%">
|
210
|
-
<a href="https://github.com/kaicataldo">
|
211
|
-
<img src="https://github.com/kaicataldo.png?s=75" width="75" height="75"><br />
|
212
|
-
Kai Cataldo
|
213
|
-
</a>
|
214
|
-
</td><td align="center" valign="top" width="11%">
|
215
210
|
<a href="https://github.com/mdjermanovic">
|
216
211
|
<img src="https://github.com/mdjermanovic.png?s=75" width="75" height="75"><br />
|
217
212
|
Milos Djermanovic
|
@@ -265,9 +260,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
|
|
265
260
|
<!--sponsorsstart-->
|
266
261
|
<h3>Platinum Sponsors</h3>
|
267
262
|
<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>
|
263
|
+
<p><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.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>
|
269
264
|
<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>
|
270
|
-
<p><a href="https://writersperhour.com"><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/b282e39/logo.png" alt="Buy.Fineproxy.Org" height="32"></a> <a href="https://www.veikkaajat.com"><img src="https://images.opencollective.com/veikkaajat/
|
265
|
+
<p><a href="https://thestandarddaily.com/"><img src="https://images.opencollective.com/eric-watson/db4e598/avatar.png" alt="The Standard Daily" height="32"></a> <a href="https://writersperhour.com"><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/b282e39/logo.png" alt="Buy.Fineproxy.Org" height="32"></a> <a href="https://www.veikkaajat.com"><img src="https://images.opencollective.com/veikkaajat/3777f94/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.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a></p>
|
271
266
|
<!--sponsorsend-->
|
272
267
|
|
273
268
|
## <a name="technology-sponsors"></a>Technology Sponsors
|
package/bin/eslint.js
CHANGED
@@ -14,7 +14,7 @@ require("v8-compile-cache");
|
|
14
14
|
|
15
15
|
// must do this initialization *before* other requires in order to work
|
16
16
|
if (process.argv.includes("--debug")) {
|
17
|
-
require("debug").enable("eslint:*,-eslint:code-path");
|
17
|
+
require("debug").enable("eslint:*,-eslint:code-path,eslintrc:*");
|
18
18
|
}
|
19
19
|
|
20
20
|
//------------------------------------------------------------------------------
|
package/lib/eslint/eslint.js
CHANGED
@@ -272,7 +272,7 @@ function processOptions({
|
|
272
272
|
errors.push("'rulePaths' must be an array of non-empty strings.");
|
273
273
|
}
|
274
274
|
if (typeof useEslintrc !== "boolean") {
|
275
|
-
errors.push("'
|
275
|
+
errors.push("'useEslintrc' must be a boolean.");
|
276
276
|
}
|
277
277
|
|
278
278
|
if (errors.length > 0) {
|
@@ -563,7 +563,7 @@ class ESLint {
|
|
563
563
|
|
564
564
|
/**
|
565
565
|
* Returns the formatter representing the given formatter name.
|
566
|
-
* @param {string} [name] The name of the
|
566
|
+
* @param {string} [name] The name of the formatter to load.
|
567
567
|
* The following values are allowed:
|
568
568
|
* - `undefined` ... Load `stylish` builtin formatter.
|
569
569
|
* - A builtin formatter name ... Load the builtin formatter.
|
@@ -191,7 +191,7 @@ module.exports = {
|
|
191
191
|
}
|
192
192
|
|
193
193
|
/*
|
194
|
-
* If the first token of the
|
194
|
+
* If the first token of the return value is `{` or the return value is a sequence expression,
|
195
195
|
* enclose the return value by parentheses to avoid syntax error.
|
196
196
|
*/
|
197
197
|
if (astUtils.isOpeningBraceToken(firstValueToken) || blockBody[0].argument.type === "SequenceExpression" || (funcInfo.hasInOperator && isInsideForLoopInitializer(node))) {
|
@@ -59,9 +59,9 @@ module.exports = {
|
|
59
59
|
}
|
60
60
|
|
61
61
|
/**
|
62
|
-
* Check to see if a node contains only
|
62
|
+
* Check to see if a node contains only identifiers
|
63
63
|
* @param {ASTNode} node The node to check
|
64
|
-
* @returns {boolean} Whether or not the node contains only
|
64
|
+
* @returns {boolean} Whether or not the node contains only identifiers
|
65
65
|
*/
|
66
66
|
function containsOnlyIdentifiers(node) {
|
67
67
|
if (node.type === "Identifier") {
|
@@ -46,7 +46,7 @@ module.exports = {
|
|
46
46
|
const sourceCode = context.getSourceCode();
|
47
47
|
|
48
48
|
/**
|
49
|
-
* Reports if the dot between object and property is on the correct
|
49
|
+
* Reports if the dot between object and property is on the correct location.
|
50
50
|
* @param {ASTNode} node The `MemberExpression` node.
|
51
51
|
* @returns {void}
|
52
52
|
*/
|
@@ -131,7 +131,7 @@ module.exports = {
|
|
131
131
|
return null;
|
132
132
|
}
|
133
133
|
|
134
|
-
// If `?.`
|
134
|
+
// If `?.` exists, it doesn't hide no-unexpected-multiline errors
|
135
135
|
if (node.optional) {
|
136
136
|
return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], "?.");
|
137
137
|
}
|
@@ -177,7 +177,7 @@ module.exports = {
|
|
177
177
|
/*
|
178
178
|
* Only autofix if there is no newline
|
179
179
|
* https://github.com/eslint/eslint/issues/7787
|
180
|
-
* But if `?.`
|
180
|
+
* But if `?.` exists, it doesn't hide no-unexpected-multiline errors
|
181
181
|
*/
|
182
182
|
if (!node.optional) {
|
183
183
|
return null;
|
package/lib/rules/index.js
CHANGED
@@ -169,6 +169,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
169
169
|
"no-new-require": () => require("./no-new-require"),
|
170
170
|
"no-new-symbol": () => require("./no-new-symbol"),
|
171
171
|
"no-new-wrappers": () => require("./no-new-wrappers"),
|
172
|
+
"no-nonoctal-decimal-escape": () => require("./no-nonoctal-decimal-escape"),
|
172
173
|
"no-obj-calls": () => require("./no-obj-calls"),
|
173
174
|
"no-octal": () => require("./no-octal"),
|
174
175
|
"no-octal-escape": () => require("./no-octal-escape"),
|
@@ -217,6 +218,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
217
218
|
"no-unreachable-loop": () => require("./no-unreachable-loop"),
|
218
219
|
"no-unsafe-finally": () => require("./no-unsafe-finally"),
|
219
220
|
"no-unsafe-negation": () => require("./no-unsafe-negation"),
|
221
|
+
"no-unsafe-optional-chaining": () => require("./no-unsafe-optional-chaining"),
|
220
222
|
"no-unused-expressions": () => require("./no-unused-expressions"),
|
221
223
|
"no-unused-labels": () => require("./no-unused-labels"),
|
222
224
|
"no-unused-vars": () => require("./no-unused-vars"),
|
@@ -27,19 +27,22 @@ module.exports = {
|
|
27
27
|
enum: ["always", "always-multiline", "never"]
|
28
28
|
}
|
29
29
|
],
|
30
|
+
|
30
31
|
messages: {
|
31
32
|
expectedTestCons: "Expected newline between test and consequent of ternary expression.",
|
32
33
|
expectedConsAlt: "Expected newline between consequent and alternate of ternary expression.",
|
33
34
|
unexpectedTestCons: "Unexpected newline between test and consequent of ternary expression.",
|
34
35
|
unexpectedConsAlt: "Unexpected newline between consequent and alternate of ternary expression."
|
35
|
-
}
|
36
|
+
},
|
37
|
+
|
38
|
+
fixable: "whitespace"
|
36
39
|
},
|
37
40
|
|
38
41
|
create(context) {
|
42
|
+
const sourceCode = context.getSourceCode();
|
39
43
|
const option = context.options[0];
|
40
44
|
const multiline = option !== "never";
|
41
45
|
const allowSingleLine = option === "always-multiline";
|
42
|
-
const sourceCode = context.getSourceCode();
|
43
46
|
|
44
47
|
//--------------------------------------------------------------------------
|
45
48
|
// Public
|
@@ -59,6 +62,8 @@ module.exports = {
|
|
59
62
|
const areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfTest, firstTokenOfConsequent);
|
60
63
|
const areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfConsequent, firstTokenOfAlternate);
|
61
64
|
|
65
|
+
const hasComments = !!sourceCode.getCommentsInside(node).length;
|
66
|
+
|
62
67
|
if (!multiline) {
|
63
68
|
if (!areTestAndConsequentOnSameLine) {
|
64
69
|
context.report({
|
@@ -67,7 +72,24 @@ module.exports = {
|
|
67
72
|
start: firstTokenOfTest.loc.start,
|
68
73
|
end: lastTokenOfTest.loc.end
|
69
74
|
},
|
70
|
-
messageId: "unexpectedTestCons"
|
75
|
+
messageId: "unexpectedTestCons",
|
76
|
+
fix: fixer => {
|
77
|
+
if (hasComments) {
|
78
|
+
return null;
|
79
|
+
}
|
80
|
+
const fixers = [];
|
81
|
+
const areTestAndQuestionOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfTest, questionToken);
|
82
|
+
const areQuestionAndConsOnSameLine = astUtils.isTokenOnSameLine(questionToken, firstTokenOfConsequent);
|
83
|
+
|
84
|
+
if (!areTestAndQuestionOnSameLine) {
|
85
|
+
fixers.push(fixer.removeRange([lastTokenOfTest.range[1], questionToken.range[0]]));
|
86
|
+
}
|
87
|
+
if (!areQuestionAndConsOnSameLine) {
|
88
|
+
fixers.push(fixer.removeRange([questionToken.range[1], firstTokenOfConsequent.range[0]]));
|
89
|
+
}
|
90
|
+
|
91
|
+
return fixers;
|
92
|
+
}
|
71
93
|
});
|
72
94
|
}
|
73
95
|
|
@@ -78,7 +100,24 @@ module.exports = {
|
|
78
100
|
start: firstTokenOfConsequent.loc.start,
|
79
101
|
end: lastTokenOfConsequent.loc.end
|
80
102
|
},
|
81
|
-
messageId: "unexpectedConsAlt"
|
103
|
+
messageId: "unexpectedConsAlt",
|
104
|
+
fix: fixer => {
|
105
|
+
if (hasComments) {
|
106
|
+
return null;
|
107
|
+
}
|
108
|
+
const fixers = [];
|
109
|
+
const areConsAndColonOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfConsequent, colonToken);
|
110
|
+
const areColonAndAltOnSameLine = astUtils.isTokenOnSameLine(colonToken, firstTokenOfAlternate);
|
111
|
+
|
112
|
+
if (!areConsAndColonOnSameLine) {
|
113
|
+
fixers.push(fixer.removeRange([lastTokenOfConsequent.range[1], colonToken.range[0]]));
|
114
|
+
}
|
115
|
+
if (!areColonAndAltOnSameLine) {
|
116
|
+
fixers.push(fixer.removeRange([colonToken.range[1], firstTokenOfAlternate.range[0]]));
|
117
|
+
}
|
118
|
+
|
119
|
+
return fixers;
|
120
|
+
}
|
82
121
|
});
|
83
122
|
}
|
84
123
|
} else {
|
@@ -93,7 +132,16 @@ module.exports = {
|
|
93
132
|
start: firstTokenOfTest.loc.start,
|
94
133
|
end: lastTokenOfTest.loc.end
|
95
134
|
},
|
96
|
-
messageId: "expectedTestCons"
|
135
|
+
messageId: "expectedTestCons",
|
136
|
+
fix: fixer => (hasComments ? null : (
|
137
|
+
fixer.replaceTextRange(
|
138
|
+
[
|
139
|
+
lastTokenOfTest.range[1],
|
140
|
+
questionToken.range[0]
|
141
|
+
],
|
142
|
+
"\n"
|
143
|
+
)
|
144
|
+
))
|
97
145
|
});
|
98
146
|
}
|
99
147
|
|
@@ -104,7 +152,16 @@ module.exports = {
|
|
104
152
|
start: firstTokenOfConsequent.loc.start,
|
105
153
|
end: lastTokenOfConsequent.loc.end
|
106
154
|
},
|
107
|
-
messageId: "expectedConsAlt"
|
155
|
+
messageId: "expectedConsAlt",
|
156
|
+
fix: (fixer => (hasComments ? null : (
|
157
|
+
fixer.replaceTextRange(
|
158
|
+
[
|
159
|
+
lastTokenOfConsequent.range[1],
|
160
|
+
colonToken.range[0]
|
161
|
+
],
|
162
|
+
"\n"
|
163
|
+
)
|
164
|
+
)))
|
108
165
|
});
|
109
166
|
}
|
110
167
|
}
|
@@ -106,10 +106,15 @@ module.exports = {
|
|
106
106
|
*/
|
107
107
|
return operator === node.operator &&
|
108
108
|
(
|
109
|
-
isLogicalIdentity(node.left,
|
110
|
-
isLogicalIdentity(node.right,
|
109
|
+
isLogicalIdentity(node.left, operator) ||
|
110
|
+
isLogicalIdentity(node.right, operator)
|
111
111
|
);
|
112
112
|
|
113
|
+
case "AssignmentExpression":
|
114
|
+
return ["||=", "&&="].includes(node.operator) &&
|
115
|
+
operator === node.operator.slice(0, -1) &&
|
116
|
+
isLogicalIdentity(node.right, operator);
|
117
|
+
|
113
118
|
// no default
|
114
119
|
}
|
115
120
|
return false;
|
@@ -147,12 +152,18 @@ module.exports = {
|
|
147
152
|
}
|
148
153
|
|
149
154
|
case "UnaryExpression":
|
150
|
-
if (
|
155
|
+
if (
|
156
|
+
node.operator === "void" ||
|
157
|
+
node.operator === "typeof" && inBooleanPosition
|
158
|
+
) {
|
151
159
|
return true;
|
152
160
|
}
|
153
161
|
|
154
|
-
|
155
|
-
isConstant(node.argument, true);
|
162
|
+
if (node.operator === "!") {
|
163
|
+
return isConstant(node.argument, true);
|
164
|
+
}
|
165
|
+
|
166
|
+
return isConstant(node.argument, false);
|
156
167
|
|
157
168
|
case "BinaryExpression":
|
158
169
|
return isConstant(node.left, false) &&
|
@@ -171,7 +182,15 @@ module.exports = {
|
|
171
182
|
}
|
172
183
|
|
173
184
|
case "AssignmentExpression":
|
174
|
-
|
185
|
+
if (node.operator === "=") {
|
186
|
+
return isConstant(node.right, inBooleanPosition);
|
187
|
+
}
|
188
|
+
|
189
|
+
if (["||=", "&&="].includes(node.operator) && inBooleanPosition) {
|
190
|
+
return isLogicalIdentity(node.right, node.operator.slice(0, -1));
|
191
|
+
}
|
192
|
+
|
193
|
+
return false;
|
175
194
|
|
176
195
|
case "SequenceExpression":
|
177
196
|
return isConstant(node.expressions[node.expressions.length - 1], inBooleanPosition);
|
@@ -138,7 +138,7 @@ module.exports = {
|
|
138
138
|
}
|
139
139
|
|
140
140
|
/*
|
141
|
-
* `identifierNode.parent` is a
|
141
|
+
* `identifierNode.parent` is a MemberExpression `*.prototype`.
|
142
142
|
* If it's an optional member access, it may be wrapped by a `ChainExpression` node.
|
143
143
|
*/
|
144
144
|
const prototypeNode =
|
@@ -472,20 +472,34 @@ module.exports = {
|
|
472
472
|
const callee = node.callee;
|
473
473
|
|
474
474
|
if (hasExcessParensWithPrecedence(callee, precedence(node))) {
|
475
|
-
const hasNewParensException = callee.type === "NewExpression" && !isNewExpressionWithParens(callee);
|
476
|
-
|
477
475
|
if (
|
478
476
|
hasDoubleExcessParens(callee) ||
|
479
|
-
!isIIFE(node) &&
|
480
|
-
!hasNewParensException &&
|
481
477
|
!(
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
478
|
+
isIIFE(node) ||
|
479
|
+
|
480
|
+
// (new A)(); new (new A)();
|
481
|
+
(
|
482
|
+
callee.type === "NewExpression" &&
|
483
|
+
!isNewExpressionWithParens(callee) &&
|
484
|
+
!(
|
485
|
+
node.type === "NewExpression" &&
|
486
|
+
!isNewExpressionWithParens(node)
|
487
|
+
)
|
488
|
+
) ||
|
489
|
+
|
490
|
+
// new (a().b)(); new (a.b().c);
|
491
|
+
(
|
492
|
+
node.type === "NewExpression" &&
|
493
|
+
callee.type === "MemberExpression" &&
|
494
|
+
doesMemberExpressionContainCallExpression(callee)
|
495
|
+
) ||
|
496
|
+
|
497
|
+
// (a?.b)(); (a?.())();
|
498
|
+
(
|
499
|
+
!node.optional &&
|
500
|
+
callee.type === "ChainExpression"
|
501
|
+
)
|
502
|
+
)
|
489
503
|
) {
|
490
504
|
report(node.callee);
|
491
505
|
}
|
@@ -511,7 +525,7 @@ module.exports = {
|
|
511
525
|
|
512
526
|
if (!shouldSkipLeft && hasExcessParens(node.left)) {
|
513
527
|
if (
|
514
|
-
!(node.left.type
|
528
|
+
!(["AwaitExpression", "UnaryExpression"].includes(node.left.type) && isExponentiation) &&
|
515
529
|
!astUtils.isMixedLogicalAndCoalesceExpressions(node.left, node) &&
|
516
530
|
(leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation)) ||
|
517
531
|
isParenthesisedTwice(node.left)
|
@@ -97,10 +97,10 @@ function isIterationVariable(node) {
|
|
97
97
|
* - `Object.defineProperties`
|
98
98
|
* - `Object.freeze`
|
99
99
|
* - `Object.setPrototypeOf`
|
100
|
-
* - `
|
101
|
-
* - `
|
102
|
-
* - `
|
103
|
-
* - `
|
100
|
+
* - `Reflect.defineProperty`
|
101
|
+
* - `Reflect.deleteProperty`
|
102
|
+
* - `Reflect.set`
|
103
|
+
* - `Reflect.setPrototypeOf`
|
104
104
|
* @param {ASTNode} node The node to check.
|
105
105
|
* @param {Scope} scope A `escope.Scope` object to find variable (whichever).
|
106
106
|
* @returns {boolean} `true` if the node is at the first argument of a well-known mutation function.
|
@@ -9,7 +9,7 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const RegExpValidator = require("regexpp").RegExpValidator;
|
12
|
-
const validator = new RegExpValidator(
|
12
|
+
const validator = new RegExpValidator();
|
13
13
|
const validFlags = /[gimuys]/gu;
|
14
14
|
const undefined1 = void 0;
|
15
15
|
|
@@ -82,7 +82,7 @@ module.exports = {
|
|
82
82
|
const commentNodes = sourceCode.getAllComments();
|
83
83
|
|
84
84
|
/**
|
85
|
-
* Removes errors that occur inside
|
85
|
+
* Removes errors that occur inside the given node
|
86
86
|
* @param {ASTNode} node to check for matching errors.
|
87
87
|
* @returns {void}
|
88
88
|
* @private
|
@@ -91,14 +91,12 @@ module.exports = {
|
|
91
91
|
const locStart = node.loc.start;
|
92
92
|
const locEnd = node.loc.end;
|
93
93
|
|
94
|
-
errors = errors.filter(({ loc: { start:
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
return true;
|
101
|
-
});
|
94
|
+
errors = errors.filter(({ loc: { start: errorLocStart } }) => (
|
95
|
+
errorLocStart.line < locStart.line ||
|
96
|
+
errorLocStart.line === locStart.line && errorLocStart.column < locStart.column ||
|
97
|
+
errorLocStart.line === locEnd.line && errorLocStart.column >= locEnd.column ||
|
98
|
+
errorLocStart.line > locEnd.line
|
99
|
+
));
|
102
100
|
}
|
103
101
|
|
104
102
|
/**
|
@@ -0,0 +1,147 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Rule to disallow `\8` and `\9` escape sequences in string literals.
|
3
|
+
* @author Milos Djermanovic
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Helpers
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const QUICK_TEST_REGEX = /\\[89]/u;
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Returns unicode escape sequence that represents the given character.
|
16
|
+
* @param {string} character A single code unit.
|
17
|
+
* @returns {string} "\uXXXX" sequence.
|
18
|
+
*/
|
19
|
+
function getUnicodeEscape(character) {
|
20
|
+
return `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
21
|
+
}
|
22
|
+
|
23
|
+
//------------------------------------------------------------------------------
|
24
|
+
// Rule Definition
|
25
|
+
//------------------------------------------------------------------------------
|
26
|
+
|
27
|
+
module.exports = {
|
28
|
+
meta: {
|
29
|
+
type: "suggestion",
|
30
|
+
|
31
|
+
docs: {
|
32
|
+
description: "disallow `\\8` and `\\9` escape sequences in string literals",
|
33
|
+
category: "Best Practices",
|
34
|
+
recommended: false,
|
35
|
+
url: "https://eslint.org/docs/rules/no-nonoctal-decimal-escape",
|
36
|
+
suggestion: true
|
37
|
+
},
|
38
|
+
|
39
|
+
schema: [],
|
40
|
+
|
41
|
+
messages: {
|
42
|
+
decimalEscape: "Don't use '{{decimalEscape}}' escape sequence.",
|
43
|
+
|
44
|
+
// suggestions
|
45
|
+
refactor: "Replace '{{original}}' with '{{replacement}}'. This maintains the current functionality.",
|
46
|
+
escapeBackslash: "Replace '{{original}}' with '{{replacement}}' to include the actual backslash character."
|
47
|
+
}
|
48
|
+
},
|
49
|
+
|
50
|
+
create(context) {
|
51
|
+
const sourceCode = context.getSourceCode();
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Creates a new Suggestion object.
|
55
|
+
* @param {string} messageId "refactor" or "escapeBackslash".
|
56
|
+
* @param {int[]} range The range to replace.
|
57
|
+
* @param {string} replacement New text for the range.
|
58
|
+
* @returns {Object} Suggestion
|
59
|
+
*/
|
60
|
+
function createSuggestion(messageId, range, replacement) {
|
61
|
+
return {
|
62
|
+
messageId,
|
63
|
+
data: {
|
64
|
+
original: sourceCode.getText().slice(...range),
|
65
|
+
replacement
|
66
|
+
},
|
67
|
+
fix(fixer) {
|
68
|
+
return fixer.replaceTextRange(range, replacement);
|
69
|
+
}
|
70
|
+
};
|
71
|
+
}
|
72
|
+
|
73
|
+
return {
|
74
|
+
Literal(node) {
|
75
|
+
if (typeof node.value !== "string") {
|
76
|
+
return;
|
77
|
+
}
|
78
|
+
|
79
|
+
if (!QUICK_TEST_REGEX.test(node.raw)) {
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
|
83
|
+
const regex = /(?:[^\\]|(?<previousEscape>\\.))*?(?<decimalEscape>\\[89])/suy;
|
84
|
+
let match;
|
85
|
+
|
86
|
+
while ((match = regex.exec(node.raw))) {
|
87
|
+
const { previousEscape, decimalEscape } = match.groups;
|
88
|
+
const decimalEscapeRangeEnd = node.range[0] + match.index + match[0].length;
|
89
|
+
const decimalEscapeRangeStart = decimalEscapeRangeEnd - decimalEscape.length;
|
90
|
+
const decimalEscapeRange = [decimalEscapeRangeStart, decimalEscapeRangeEnd];
|
91
|
+
const suggest = [];
|
92
|
+
|
93
|
+
// When `regex` is matched, `previousEscape` can only capture characters adjacent to `decimalEscape`
|
94
|
+
if (previousEscape === "\\0") {
|
95
|
+
|
96
|
+
/*
|
97
|
+
* Now we have a NULL escape "\0" immediately followed by a decimal escape, e.g.: "\0\8".
|
98
|
+
* Fixing this to "\08" would turn "\0" into a legacy octal escape. To avoid producing
|
99
|
+
* an octal escape while fixing a decimal escape, we provide different suggestions.
|
100
|
+
*/
|
101
|
+
suggest.push(
|
102
|
+
createSuggestion( // "\0\8" -> "\u00008"
|
103
|
+
"refactor",
|
104
|
+
[decimalEscapeRangeStart - previousEscape.length, decimalEscapeRangeEnd],
|
105
|
+
`${getUnicodeEscape("\0")}${decimalEscape[1]}`
|
106
|
+
),
|
107
|
+
createSuggestion( // "\8" -> "\u0038"
|
108
|
+
"refactor",
|
109
|
+
decimalEscapeRange,
|
110
|
+
getUnicodeEscape(decimalEscape[1])
|
111
|
+
)
|
112
|
+
);
|
113
|
+
} else {
|
114
|
+
suggest.push(
|
115
|
+
createSuggestion( // "\8" -> "8"
|
116
|
+
"refactor",
|
117
|
+
decimalEscapeRange,
|
118
|
+
decimalEscape[1]
|
119
|
+
)
|
120
|
+
);
|
121
|
+
}
|
122
|
+
|
123
|
+
suggest.push(
|
124
|
+
createSuggestion( // "\8" -> "\\8"
|
125
|
+
"escapeBackslash",
|
126
|
+
decimalEscapeRange,
|
127
|
+
`\\${decimalEscape}`
|
128
|
+
)
|
129
|
+
);
|
130
|
+
|
131
|
+
context.report({
|
132
|
+
node,
|
133
|
+
loc: {
|
134
|
+
start: sourceCode.getLocFromIndex(decimalEscapeRangeStart),
|
135
|
+
end: sourceCode.getLocFromIndex(decimalEscapeRangeEnd)
|
136
|
+
},
|
137
|
+
messageId: "decimalEscape",
|
138
|
+
data: {
|
139
|
+
decimalEscape
|
140
|
+
},
|
141
|
+
suggest
|
142
|
+
});
|
143
|
+
}
|
144
|
+
}
|
145
|
+
};
|
146
|
+
}
|
147
|
+
};
|
@@ -45,7 +45,7 @@ module.exports = {
|
|
45
45
|
|
46
46
|
/**
|
47
47
|
* Checks and reports given exported identifier.
|
48
|
-
* @param {ASTNode} node exported `
|
48
|
+
* @param {ASTNode} node exported `Identifier` node to check.
|
49
49
|
* @returns {void}
|
50
50
|
*/
|
51
51
|
function checkExportedName(node) {
|
@@ -171,7 +171,7 @@ module.exports = {
|
|
171
171
|
/**
|
172
172
|
* Removes the top of stack item.
|
173
173
|
*
|
174
|
-
* And this
|
174
|
+
* And this traverses all segments of this code path then reports every
|
175
175
|
* invalid node.
|
176
176
|
* @param {CodePath} codePath A code path which was ended.
|
177
177
|
* @returns {void}
|
@@ -0,0 +1,205 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Rule to disallow unsafe optional chaining
|
3
|
+
* @author Yeon JuAn
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
const UNSAFE_ARITHMETIC_OPERATORS = new Set(["+", "-", "/", "*", "%", "**"]);
|
9
|
+
const UNSAFE_ASSIGNMENT_OPERATORS = new Set(["+=", "-=", "/=", "*=", "%=", "**="]);
|
10
|
+
const UNSAFE_RELATIONAL_OPERATORS = new Set(["in", "instanceof"]);
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Checks whether a node is a destructuring pattern or not
|
14
|
+
* @param {ASTNode} node node to check
|
15
|
+
* @returns {boolean} `true` if a node is a destructuring pattern, otherwise `false`
|
16
|
+
*/
|
17
|
+
function isDestructuringPattern(node) {
|
18
|
+
return node.type === "ObjectPattern" || node.type === "ArrayPattern";
|
19
|
+
}
|
20
|
+
|
21
|
+
module.exports = {
|
22
|
+
meta: {
|
23
|
+
type: "problem",
|
24
|
+
|
25
|
+
docs: {
|
26
|
+
description: "disallow use of optional chaining in contexts where the `undefined` value is not allowed",
|
27
|
+
category: "Possible Errors",
|
28
|
+
recommended: false,
|
29
|
+
url: "https://eslint.org/docs/rules/no-unsafe-optional-chaining"
|
30
|
+
},
|
31
|
+
schema: [{
|
32
|
+
type: "object",
|
33
|
+
properties: {
|
34
|
+
disallowArithmeticOperators: {
|
35
|
+
type: "boolean",
|
36
|
+
default: false
|
37
|
+
}
|
38
|
+
},
|
39
|
+
additionalProperties: false
|
40
|
+
}],
|
41
|
+
fixable: null,
|
42
|
+
messages: {
|
43
|
+
unsafeOptionalChain: "Unsafe usage of optional chaining. If it short-circuits with 'undefined' the evaluation will throw TypeError.",
|
44
|
+
unsafeArithmetic: "Unsafe arithmetic operation on optional chaining. It can result in NaN."
|
45
|
+
}
|
46
|
+
},
|
47
|
+
|
48
|
+
create(context) {
|
49
|
+
const options = context.options[0] || {};
|
50
|
+
const disallowArithmeticOperators = (options.disallowArithmeticOperators) || false;
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Reports unsafe usage of optional chaining
|
54
|
+
* @param {ASTNode} node node to report
|
55
|
+
* @returns {void}
|
56
|
+
*/
|
57
|
+
function reportUnsafeUsage(node) {
|
58
|
+
context.report({
|
59
|
+
messageId: "unsafeOptionalChain",
|
60
|
+
node
|
61
|
+
});
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Reports unsafe arithmetic operation on optional chaining
|
66
|
+
* @param {ASTNode} node node to report
|
67
|
+
* @returns {void}
|
68
|
+
*/
|
69
|
+
function reportUnsafeArithmetic(node) {
|
70
|
+
context.report({
|
71
|
+
messageId: "unsafeArithmetic",
|
72
|
+
node
|
73
|
+
});
|
74
|
+
}
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Checks and reports if a node can short-circuit with `undefined` by optional chaining.
|
78
|
+
* @param {ASTNode} [node] node to check
|
79
|
+
* @param {Function} reportFunc report function
|
80
|
+
* @returns {void}
|
81
|
+
*/
|
82
|
+
function checkUndefinedShortCircuit(node, reportFunc) {
|
83
|
+
if (!node) {
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
switch (node.type) {
|
87
|
+
case "LogicalExpression":
|
88
|
+
if (node.operator === "||" || node.operator === "??") {
|
89
|
+
checkUndefinedShortCircuit(node.right, reportFunc);
|
90
|
+
} else if (node.operator === "&&") {
|
91
|
+
checkUndefinedShortCircuit(node.left, reportFunc);
|
92
|
+
checkUndefinedShortCircuit(node.right, reportFunc);
|
93
|
+
}
|
94
|
+
break;
|
95
|
+
case "SequenceExpression":
|
96
|
+
checkUndefinedShortCircuit(
|
97
|
+
node.expressions[node.expressions.length - 1],
|
98
|
+
reportFunc
|
99
|
+
);
|
100
|
+
break;
|
101
|
+
case "ConditionalExpression":
|
102
|
+
checkUndefinedShortCircuit(node.consequent, reportFunc);
|
103
|
+
checkUndefinedShortCircuit(node.alternate, reportFunc);
|
104
|
+
break;
|
105
|
+
case "AwaitExpression":
|
106
|
+
checkUndefinedShortCircuit(node.argument, reportFunc);
|
107
|
+
break;
|
108
|
+
case "ChainExpression":
|
109
|
+
reportFunc(node);
|
110
|
+
break;
|
111
|
+
default:
|
112
|
+
break;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Checks unsafe usage of optional chaining
|
118
|
+
* @param {ASTNode} node node to check
|
119
|
+
* @returns {void}
|
120
|
+
*/
|
121
|
+
function checkUnsafeUsage(node) {
|
122
|
+
checkUndefinedShortCircuit(node, reportUnsafeUsage);
|
123
|
+
}
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Checks unsafe arithmetic operations on optional chaining
|
127
|
+
* @param {ASTNode} node node to check
|
128
|
+
* @returns {void}
|
129
|
+
*/
|
130
|
+
function checkUnsafeArithmetic(node) {
|
131
|
+
checkUndefinedShortCircuit(node, reportUnsafeArithmetic);
|
132
|
+
}
|
133
|
+
|
134
|
+
return {
|
135
|
+
"AssignmentExpression, AssignmentPattern"(node) {
|
136
|
+
if (isDestructuringPattern(node.left)) {
|
137
|
+
checkUnsafeUsage(node.right);
|
138
|
+
}
|
139
|
+
},
|
140
|
+
"ClassDeclaration, ClassExpression"(node) {
|
141
|
+
checkUnsafeUsage(node.superClass);
|
142
|
+
},
|
143
|
+
CallExpression(node) {
|
144
|
+
if (!node.optional) {
|
145
|
+
checkUnsafeUsage(node.callee);
|
146
|
+
}
|
147
|
+
},
|
148
|
+
NewExpression(node) {
|
149
|
+
checkUnsafeUsage(node.callee);
|
150
|
+
},
|
151
|
+
VariableDeclarator(node) {
|
152
|
+
if (isDestructuringPattern(node.id)) {
|
153
|
+
checkUnsafeUsage(node.init);
|
154
|
+
}
|
155
|
+
},
|
156
|
+
MemberExpression(node) {
|
157
|
+
if (!node.optional) {
|
158
|
+
checkUnsafeUsage(node.object);
|
159
|
+
}
|
160
|
+
},
|
161
|
+
TaggedTemplateExpression(node) {
|
162
|
+
checkUnsafeUsage(node.tag);
|
163
|
+
},
|
164
|
+
ForOfStatement(node) {
|
165
|
+
checkUnsafeUsage(node.right);
|
166
|
+
},
|
167
|
+
SpreadElement(node) {
|
168
|
+
if (node.parent && node.parent.type !== "ObjectExpression") {
|
169
|
+
checkUnsafeUsage(node.argument);
|
170
|
+
}
|
171
|
+
},
|
172
|
+
BinaryExpression(node) {
|
173
|
+
if (UNSAFE_RELATIONAL_OPERATORS.has(node.operator)) {
|
174
|
+
checkUnsafeUsage(node.right);
|
175
|
+
}
|
176
|
+
if (
|
177
|
+
disallowArithmeticOperators &&
|
178
|
+
UNSAFE_ARITHMETIC_OPERATORS.has(node.operator)
|
179
|
+
) {
|
180
|
+
checkUnsafeArithmetic(node.right);
|
181
|
+
checkUnsafeArithmetic(node.left);
|
182
|
+
}
|
183
|
+
},
|
184
|
+
WithStatement(node) {
|
185
|
+
checkUnsafeUsage(node.object);
|
186
|
+
},
|
187
|
+
UnaryExpression(node) {
|
188
|
+
if (
|
189
|
+
disallowArithmeticOperators &&
|
190
|
+
UNSAFE_ARITHMETIC_OPERATORS.has(node.operator)
|
191
|
+
) {
|
192
|
+
checkUnsafeArithmetic(node.argument);
|
193
|
+
}
|
194
|
+
},
|
195
|
+
AssignmentExpression(node) {
|
196
|
+
if (
|
197
|
+
disallowArithmeticOperators &&
|
198
|
+
UNSAFE_ASSIGNMENT_OPERATORS.has(node.operator)
|
199
|
+
) {
|
200
|
+
checkUnsafeArithmetic(node.right);
|
201
|
+
}
|
202
|
+
}
|
203
|
+
};
|
204
|
+
}
|
205
|
+
};
|
@@ -162,6 +162,14 @@ module.exports = {
|
|
162
162
|
return;
|
163
163
|
}
|
164
164
|
|
165
|
+
/*
|
166
|
+
* Prevent crashing on parsers which do not require class constructor
|
167
|
+
* to have a body, e.g. typescript and flow
|
168
|
+
*/
|
169
|
+
if (!node.value.body) {
|
170
|
+
return;
|
171
|
+
}
|
172
|
+
|
165
173
|
const body = node.value.body.body;
|
166
174
|
const ctorParams = node.value.params;
|
167
175
|
const superClass = node.parent.parent.superClass;
|
@@ -109,9 +109,9 @@ module.exports = {
|
|
109
109
|
* @returns {void}
|
110
110
|
*/
|
111
111
|
function report(node, startOffset, character) {
|
112
|
-
const
|
113
|
-
const rangeStart = sourceCode.getIndexFromLoc(node.loc.start) + startOffset;
|
112
|
+
const rangeStart = node.range[0] + startOffset;
|
114
113
|
const range = [rangeStart, rangeStart + 1];
|
114
|
+
const start = sourceCode.getLocFromIndex(rangeStart);
|
115
115
|
|
116
116
|
context.report({
|
117
117
|
node,
|
@@ -172,7 +172,7 @@ module.exports = {
|
|
172
172
|
}
|
173
173
|
|
174
174
|
if (isUnnecessaryEscape && !isQuoteEscape) {
|
175
|
-
report(node, match.index
|
175
|
+
report(node, match.index, match[0].slice(1));
|
176
176
|
}
|
177
177
|
}
|
178
178
|
|
@@ -206,7 +206,7 @@ module.exports = {
|
|
206
206
|
return;
|
207
207
|
}
|
208
208
|
|
209
|
-
const value = isTemplateElement ? node
|
209
|
+
const value = isTemplateElement ? sourceCode.getText(node) : node.raw;
|
210
210
|
const pattern = /\\[^\d]/gu;
|
211
211
|
let match;
|
212
212
|
|
package/lib/rules/one-var.js
CHANGED
@@ -5,6 +5,25 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const astUtils = require("./utils/ast-utils");
|
13
|
+
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Helpers
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Determines whether the given node is in a statement list.
|
20
|
+
* @param {ASTNode} node node to check
|
21
|
+
* @returns {boolean} `true` if the given node is in a statement list
|
22
|
+
*/
|
23
|
+
function isInStatementList(node) {
|
24
|
+
return astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type);
|
25
|
+
}
|
26
|
+
|
8
27
|
//------------------------------------------------------------------------------
|
9
28
|
// Rule Definition
|
10
29
|
//------------------------------------------------------------------------------
|
@@ -268,8 +287,8 @@ module.exports = {
|
|
268
287
|
|
269
288
|
/**
|
270
289
|
* Fixer to join VariableDeclaration's into a single declaration
|
271
|
-
* @param
|
272
|
-
* @returns {Function}
|
290
|
+
* @param {VariableDeclarator[]} declarations The `VariableDeclaration` to join
|
291
|
+
* @returns {Function} The fixer function
|
273
292
|
*/
|
274
293
|
function joinDeclarations(declarations) {
|
275
294
|
const declaration = declarations[0];
|
@@ -297,10 +316,17 @@ module.exports = {
|
|
297
316
|
|
298
317
|
/**
|
299
318
|
* Fixer to split a VariableDeclaration into individual declarations
|
300
|
-
* @param
|
301
|
-
* @returns {Function}
|
319
|
+
* @param {VariableDeclaration} declaration The `VariableDeclaration` to split
|
320
|
+
* @returns {Function|null} The fixer function
|
302
321
|
*/
|
303
322
|
function splitDeclarations(declaration) {
|
323
|
+
const { parent } = declaration;
|
324
|
+
|
325
|
+
// don't autofix code such as: if (foo) var x, y;
|
326
|
+
if (!isInStatementList(parent.type === "ExportNamedDeclaration" ? parent : declaration)) {
|
327
|
+
return null;
|
328
|
+
}
|
329
|
+
|
304
330
|
return fixer => declaration.declarations.map(declarator => {
|
305
331
|
const tokenAfterDeclarator = sourceCode.getTokenAfter(declarator);
|
306
332
|
|
@@ -314,12 +340,14 @@ module.exports = {
|
|
314
340
|
return null;
|
315
341
|
}
|
316
342
|
|
343
|
+
const exportPlacement = declaration.parent.type === "ExportNamedDeclaration" ? "export " : "";
|
344
|
+
|
317
345
|
/*
|
318
346
|
* `var x,y`
|
319
347
|
* tokenAfterDeclarator ^^ afterComma
|
320
348
|
*/
|
321
349
|
if (afterComma.range[0] === tokenAfterDeclarator.range[1]) {
|
322
|
-
return fixer.replaceText(tokenAfterDeclarator, `; ${declaration.kind} `);
|
350
|
+
return fixer.replaceText(tokenAfterDeclarator, `; ${exportPlacement}${declaration.kind} `);
|
323
351
|
}
|
324
352
|
|
325
353
|
/*
|
@@ -341,11 +369,11 @@ module.exports = {
|
|
341
369
|
|
342
370
|
return fixer.replaceTextRange(
|
343
371
|
[tokenAfterDeclarator.range[0], lastComment.range[0]],
|
344
|
-
`;${sourceCode.text.slice(tokenAfterDeclarator.range[1], lastComment.range[0])}${declaration.kind} `
|
372
|
+
`;${sourceCode.text.slice(tokenAfterDeclarator.range[1], lastComment.range[0])}${exportPlacement}${declaration.kind} `
|
345
373
|
);
|
346
374
|
}
|
347
375
|
|
348
|
-
return fixer.replaceText(tokenAfterDeclarator, `; ${declaration.kind}`);
|
376
|
+
return fixer.replaceText(tokenAfterDeclarator, `; ${exportPlacement}${declaration.kind}`);
|
349
377
|
}).filter(x => x);
|
350
378
|
}
|
351
379
|
|
@@ -279,7 +279,7 @@ module.exports = {
|
|
279
279
|
* @param {ASTNode} node the AssignmentExpression node
|
280
280
|
* @returns {void}
|
281
281
|
*/
|
282
|
-
function
|
282
|
+
function checkAssignmentExpression(node) {
|
283
283
|
if (node.operator === "=") {
|
284
284
|
performCheck(node.left, node.right, node);
|
285
285
|
}
|
@@ -291,7 +291,7 @@ module.exports = {
|
|
291
291
|
|
292
292
|
return {
|
293
293
|
VariableDeclarator: checkVariableDeclarator,
|
294
|
-
AssignmentExpression:
|
294
|
+
AssignmentExpression: checkAssignmentExpression
|
295
295
|
};
|
296
296
|
}
|
297
297
|
};
|
@@ -30,6 +30,7 @@ function doesBaseNeedParens(base) {
|
|
30
30
|
astUtils.getPrecedence(base) <= PRECEDENCE_OF_EXPONENTIATION_EXPR ||
|
31
31
|
|
32
32
|
// An unary operator cannot be used immediately before an exponentiation expression
|
33
|
+
base.type === "AwaitExpression" ||
|
33
34
|
base.type === "UnaryExpression"
|
34
35
|
);
|
35
36
|
}
|
@@ -105,10 +105,10 @@ module.exports = {
|
|
105
105
|
CallExpression(node) {
|
106
106
|
const methodName = (node.callee.property || {}).name;
|
107
107
|
const isReflectCall = (node.callee.object || {}).name === "Reflect";
|
108
|
-
const
|
108
|
+
const hasReflectSubstitute = Object.prototype.hasOwnProperty.call(reflectSubstitutes, methodName);
|
109
109
|
const userConfiguredException = exceptions.indexOf(methodName) !== -1;
|
110
110
|
|
111
|
-
if (
|
111
|
+
if (hasReflectSubstitute && !isReflectCall && !userConfiguredException) {
|
112
112
|
report(node, existingNames[methodName], reflectSubstitutes[methodName]);
|
113
113
|
}
|
114
114
|
},
|
@@ -82,7 +82,7 @@ function startsWithUpperCase(s) {
|
|
82
82
|
/**
|
83
83
|
* Checks whether or not a node is a constructor.
|
84
84
|
* @param {ASTNode} node A function node to check.
|
85
|
-
* @returns {boolean}
|
85
|
+
* @returns {boolean} Whether or not a node is a constructor.
|
86
86
|
*/
|
87
87
|
function isES5Constructor(node) {
|
88
88
|
return (node.id && startsWithUpperCase(node.id.name));
|
@@ -1574,7 +1574,7 @@ module.exports = {
|
|
1574
1574
|
},
|
1575
1575
|
|
1576
1576
|
/*
|
1577
|
-
* Determine if a node has a
|
1577
|
+
* Determine if a node has a possibility to be an Error object
|
1578
1578
|
* @param {ASTNode} node ASTNode to check
|
1579
1579
|
* @returns {boolean} True if there is a chance it contains an Error obj
|
1580
1580
|
*/
|
@@ -15,7 +15,7 @@ const lodash = require("lodash");
|
|
15
15
|
// Private
|
16
16
|
//------------------------------------------------------------------------------
|
17
17
|
|
18
|
-
//
|
18
|
+
// Definitions for deprecation warnings.
|
19
19
|
const deprecationWarningMessages = {
|
20
20
|
ESLINT_LEGACY_ECMAFEATURES:
|
21
21
|
"The 'ecmaFeatures' config file property is deprecated and has no effect.",
|
package/lib/shared/types.js
CHANGED
@@ -46,9 +46,9 @@ module.exports = {};
|
|
46
46
|
/**
|
47
47
|
* @typedef {Object} OverrideConfigData
|
48
48
|
* @property {Record<string, boolean>} [env] The environment settings.
|
49
|
-
* @property {string | string[]} [excludedFiles] The glob
|
49
|
+
* @property {string | string[]} [excludedFiles] The glob patterns for excluded files.
|
50
50
|
* @property {string | string[]} [extends] The path to other config files or the package name of shareable configs.
|
51
|
-
* @property {string | string[]} files The glob
|
51
|
+
* @property {string | string[]} files The glob patterns for target files.
|
52
52
|
* @property {Record<string, GlobalConf>} [globals] The global variable settings.
|
53
53
|
* @property {boolean} [noInlineConfig] The flag that disables directive comments.
|
54
54
|
* @property {OverrideConfigData[]} [overrides] The override settings per kind of files.
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "7.
|
3
|
+
"version": "7.17.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -47,7 +47,7 @@
|
|
47
47
|
"bugs": "https://github.com/eslint/eslint/issues/",
|
48
48
|
"dependencies": {
|
49
49
|
"@babel/code-frame": "^7.0.0",
|
50
|
-
"@eslint/eslintrc": "^0.2.
|
50
|
+
"@eslint/eslintrc": "^0.2.2",
|
51
51
|
"ajv": "^6.10.0",
|
52
52
|
"chalk": "^4.0.0",
|
53
53
|
"cross-spawn": "^7.0.2",
|
@@ -57,10 +57,10 @@
|
|
57
57
|
"eslint-scope": "^5.1.1",
|
58
58
|
"eslint-utils": "^2.1.0",
|
59
59
|
"eslint-visitor-keys": "^2.0.0",
|
60
|
-
"espree": "^7.3.
|
60
|
+
"espree": "^7.3.1",
|
61
61
|
"esquery": "^1.2.0",
|
62
62
|
"esutils": "^2.0.2",
|
63
|
-
"file-entry-cache": "^
|
63
|
+
"file-entry-cache": "^6.0.0",
|
64
64
|
"functional-red-black-tree": "^1.0.1",
|
65
65
|
"glob-parent": "^5.0.0",
|
66
66
|
"globals": "^12.1.0",
|
@@ -80,7 +80,7 @@
|
|
80
80
|
"semver": "^7.2.1",
|
81
81
|
"strip-ansi": "^6.0.0",
|
82
82
|
"strip-json-comments": "^3.1.0",
|
83
|
-
"table": "^
|
83
|
+
"table": "^6.0.4",
|
84
84
|
"text-table": "^0.2.0",
|
85
85
|
"v8-compile-cache": "^2.0.3"
|
86
86
|
},
|