eslint 4.1.1 → 4.4.1
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 +106 -0
- package/bin/eslint.js +5 -4
- package/conf/category-list.json +2 -2
- package/conf/config-schema.js +3 -1
- package/conf/eslint-recommended.js +12 -14
- package/lib/cli-engine.js +4 -3
- package/lib/cli.js +12 -1
- package/lib/config/config-file.js +5 -5
- package/lib/config/config-initializer.js +123 -14
- package/lib/config/config-validator.js +43 -14
- package/lib/config/plugins.js +13 -1
- package/lib/linter.js +26 -15
- package/lib/rule-context.js +53 -41
- package/lib/rules/arrow-parens.js +5 -2
- package/lib/rules/comma-dangle.js +40 -40
- package/lib/rules/curly.js +1 -1
- package/lib/rules/dot-notation.js +9 -0
- package/lib/rules/getter-return.js +176 -0
- package/lib/rules/id-blacklist.js +7 -3
- package/lib/rules/id-match.js +8 -4
- package/lib/rules/indent-legacy.js +2 -2
- package/lib/rules/indent.js +354 -349
- package/lib/rules/key-spacing.js +2 -2
- package/lib/rules/multiline-ternary.js +8 -2
- package/lib/rules/no-cond-assign.js +7 -3
- package/lib/rules/no-constant-condition.js +62 -6
- package/lib/rules/no-debugger.js +6 -1
- package/lib/rules/no-else-return.js +1 -1
- package/lib/rules/no-extra-parens.js +24 -11
- package/lib/rules/no-inner-declarations.js +8 -4
- package/lib/rules/no-multi-spaces.js +53 -115
- package/lib/rules/no-regex-spaces.js +4 -4
- package/lib/rules/no-restricted-globals.js +50 -9
- package/lib/rules/no-restricted-properties.js +19 -11
- package/lib/rules/no-sync.js +15 -3
- package/lib/rules/no-tabs.js +8 -4
- package/lib/rules/no-underscore-dangle.js +28 -1
- package/lib/rules/object-curly-newline.js +18 -0
- package/lib/rules/object-curly-spacing.js +1 -1
- package/lib/rules/padded-blocks.js +2 -2
- package/lib/rules/padding-line-between-statements.js +1 -1
- package/lib/rules/prefer-destructuring.js +70 -32
- package/lib/rules/prefer-numeric-literals.js +36 -7
- package/lib/rules/prefer-reflect.js +8 -4
- package/lib/rules/prefer-template.js +2 -2
- package/lib/rules/space-infix-ops.js +1 -1
- package/lib/rules/spaced-comment.js +2 -2
- package/lib/rules/valid-jsdoc.js +15 -7
- package/lib/testers/rule-tester.js +23 -30
- package/lib/testers/test-parser.js +48 -0
- package/lib/util/ajv.js +29 -0
- package/lib/util/npm-util.js +9 -8
- package/lib/util/source-code-fixer.js +47 -19
- package/package.json +11 -7
- package/conf/json-schema-schema.json +0 -150
@@ -9,7 +9,8 @@
|
|
9
9
|
// Requirements
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
const
|
12
|
+
const ajv = require("../util/ajv"),
|
13
|
+
lodash = require("lodash"),
|
13
14
|
configSchema = require("../../conf/config-schema.js"),
|
14
15
|
util = require("util");
|
15
16
|
|
@@ -20,6 +21,7 @@ const validators = {
|
|
20
21
|
//------------------------------------------------------------------------------
|
21
22
|
// Private
|
22
23
|
//------------------------------------------------------------------------------
|
24
|
+
let validateSchema;
|
23
25
|
|
24
26
|
/**
|
25
27
|
* Gets a complete options schema for a rule.
|
@@ -79,7 +81,7 @@ function validateRuleSchema(id, localOptions, rulesContext) {
|
|
79
81
|
const schema = getRuleOptionsSchema(id, rulesContext);
|
80
82
|
|
81
83
|
if (!validators.rules[id] && schema) {
|
82
|
-
validators.rules[id] =
|
84
|
+
validators.rules[id] = ajv.compile(schema);
|
83
85
|
}
|
84
86
|
|
85
87
|
const validateRule = validators.rules[id];
|
@@ -87,7 +89,7 @@ function validateRuleSchema(id, localOptions, rulesContext) {
|
|
87
89
|
if (validateRule) {
|
88
90
|
validateRule(localOptions);
|
89
91
|
if (validateRule.errors) {
|
90
|
-
throw new Error(validateRule.errors.map(error => `\tValue "${error.
|
92
|
+
throw new Error(validateRule.errors.map(error => `\tValue "${error.data}" ${error.message}.\n`).join(""));
|
91
93
|
}
|
92
94
|
}
|
93
95
|
}
|
@@ -158,22 +160,45 @@ function validateRules(rulesConfig, source, rulesContext) {
|
|
158
160
|
* @returns {string} Formatted error message
|
159
161
|
*/
|
160
162
|
function formatErrors(errors) {
|
161
|
-
|
162
163
|
return errors.map(error => {
|
163
|
-
if (error.
|
164
|
-
|
164
|
+
if (error.keyword === "additionalProperties") {
|
165
|
+
const formattedPropertyPath = error.dataPath.length ? `${error.dataPath.slice(1)}.${error.params.additionalProperty}` : error.params.additionalProperty;
|
166
|
+
|
167
|
+
return `Unexpected top-level property "${formattedPropertyPath}"`;
|
165
168
|
}
|
166
|
-
if (error.
|
167
|
-
const formattedField = error.
|
168
|
-
const formattedExpectedType =
|
169
|
-
const formattedValue = JSON.stringify(error.
|
169
|
+
if (error.keyword === "type") {
|
170
|
+
const formattedField = error.dataPath.slice(1);
|
171
|
+
const formattedExpectedType = Array.isArray(error.schema) ? error.schema.join("/") : error.schema;
|
172
|
+
const formattedValue = JSON.stringify(error.data);
|
170
173
|
|
171
174
|
return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
|
172
175
|
}
|
173
|
-
|
176
|
+
|
177
|
+
const field = error.dataPath[0] === "." ? error.dataPath.slice(1) : error.dataPath;
|
178
|
+
|
179
|
+
return `"${field}" ${error.message}. Value: ${JSON.stringify(error.data)}`;
|
174
180
|
}).map(message => `\t- ${message}.\n`).join("");
|
175
181
|
}
|
176
182
|
|
183
|
+
/**
|
184
|
+
* Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted
|
185
|
+
* for each unique file path, but repeated invocations with the same file path have no effect.
|
186
|
+
* No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
|
187
|
+
* @param {string} source The name of the configuration source to report the warning for.
|
188
|
+
* @returns {void}
|
189
|
+
*/
|
190
|
+
const emitEcmaFeaturesWarning = lodash.memoize(source => {
|
191
|
+
|
192
|
+
/*
|
193
|
+
* util.deprecate seems to be the only way to emit a warning in Node 4.x while respecting the --no-warnings flag.
|
194
|
+
* (In Node 6+, process.emitWarning could be used instead.)
|
195
|
+
*/
|
196
|
+
util.deprecate(
|
197
|
+
() => {},
|
198
|
+
`[eslint] The 'ecmaFeatures' config file property is deprecated, and has no effect. (found in ${source})`
|
199
|
+
)();
|
200
|
+
});
|
201
|
+
|
177
202
|
/**
|
178
203
|
* Validates the top level properties of the config object.
|
179
204
|
* @param {Object} config The config object to validate.
|
@@ -181,10 +206,14 @@ function formatErrors(errors) {
|
|
181
206
|
* @returns {void}
|
182
207
|
*/
|
183
208
|
function validateConfigSchema(config, source) {
|
184
|
-
|
209
|
+
validateSchema = validateSchema || ajv.compile(configSchema);
|
210
|
+
|
211
|
+
if (!validateSchema(config)) {
|
212
|
+
throw new Error(`ESLint configuration in ${source} is invalid:\n${formatErrors(validateSchema.errors)}`);
|
213
|
+
}
|
185
214
|
|
186
|
-
if (
|
187
|
-
|
215
|
+
if (Object.prototype.hasOwnProperty.call(config, "ecmaFeatures")) {
|
216
|
+
emitEcmaFeaturesWarning(source);
|
188
217
|
}
|
189
218
|
}
|
190
219
|
|
package/lib/config/plugins.js
CHANGED
@@ -43,7 +43,7 @@ class Plugins {
|
|
43
43
|
* @returns {string} The name of the plugin without prefix.
|
44
44
|
*/
|
45
45
|
static removePrefix(pluginName) {
|
46
|
-
return pluginName.startsWith(PLUGIN_NAME_PREFIX) ? pluginName.
|
46
|
+
return pluginName.startsWith(PLUGIN_NAME_PREFIX) ? pluginName.slice(PLUGIN_NAME_PREFIX.length) : pluginName;
|
47
47
|
}
|
48
48
|
|
49
49
|
/**
|
@@ -156,8 +156,20 @@ class Plugins {
|
|
156
156
|
* @param {string[]} pluginNames An array of plugins names.
|
157
157
|
* @returns {void}
|
158
158
|
* @throws {Error} If a plugin cannot be loaded.
|
159
|
+
* @throws {Error} If "plugins" in config is not an array
|
159
160
|
*/
|
160
161
|
loadAll(pluginNames) {
|
162
|
+
|
163
|
+
// if "plugins" in config is not an array, throw an error so user can fix their config.
|
164
|
+
if (!Array.isArray(pluginNames)) {
|
165
|
+
const pluginNotArrayMessage = "ESLint configuration error: \"plugins\" value must be an array";
|
166
|
+
|
167
|
+
debug(`${pluginNotArrayMessage}: ${JSON.stringify(pluginNames)}`);
|
168
|
+
|
169
|
+
throw new Error(pluginNotArrayMessage);
|
170
|
+
}
|
171
|
+
|
172
|
+
// load each plugin by name
|
161
173
|
pluginNames.forEach(this.load, this);
|
162
174
|
}
|
163
175
|
}
|
package/lib/linter.js
CHANGED
@@ -70,8 +70,8 @@ function parseBooleanConfig(string, comment) {
|
|
70
70
|
let value;
|
71
71
|
|
72
72
|
if (pos !== -1) {
|
73
|
-
value = name.
|
74
|
-
name = name.
|
73
|
+
value = name.slice(pos + 1);
|
74
|
+
name = name.slice(0, pos);
|
75
75
|
}
|
76
76
|
|
77
77
|
items[name] = {
|
@@ -338,7 +338,7 @@ function modifyConfigsFromComments(filename, ast, config, linterContext) {
|
|
338
338
|
const match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(value);
|
339
339
|
|
340
340
|
if (match) {
|
341
|
-
value = value.
|
341
|
+
value = value.slice(match.index + match[1].length);
|
342
342
|
|
343
343
|
if (comment.type === "Block") {
|
344
344
|
switch (match[1]) {
|
@@ -519,8 +519,11 @@ function createStubRule(message) {
|
|
519
519
|
*/
|
520
520
|
function createRuleModule(context) {
|
521
521
|
return {
|
522
|
-
Program(
|
523
|
-
context.report(
|
522
|
+
Program() {
|
523
|
+
context.report({
|
524
|
+
loc: { line: 1, column: 0 },
|
525
|
+
message
|
526
|
+
});
|
524
527
|
}
|
525
528
|
};
|
526
529
|
}
|
@@ -1197,6 +1200,7 @@ class Linter extends EventEmitter {
|
|
1197
1200
|
* @param {string} options.filename The filename from which the text was read.
|
1198
1201
|
* @param {boolean} options.allowInlineConfig Flag indicating if inline comments
|
1199
1202
|
* should be allowed.
|
1203
|
+
* @param {boolean|Function} options.fix Determines whether fixes should be applied
|
1200
1204
|
* @returns {Object} The result of the fix operation as returned from the
|
1201
1205
|
* SourceCodeFixer.
|
1202
1206
|
*/
|
@@ -1205,6 +1209,8 @@ class Linter extends EventEmitter {
|
|
1205
1209
|
fixedResult,
|
1206
1210
|
fixed = false,
|
1207
1211
|
passNumber = 0;
|
1212
|
+
const debugTextDescription = options && options.filename || `${text.slice(0, 10)}...`;
|
1213
|
+
const shouldFix = options && options.fix || true;
|
1208
1214
|
|
1209
1215
|
/**
|
1210
1216
|
* This loop continues until one of the following is true:
|
@@ -1218,11 +1224,11 @@ class Linter extends EventEmitter {
|
|
1218
1224
|
do {
|
1219
1225
|
passNumber++;
|
1220
1226
|
|
1221
|
-
debug(`Linting code for ${
|
1227
|
+
debug(`Linting code for ${debugTextDescription} (pass ${passNumber})`);
|
1222
1228
|
messages = this.verify(text, config, options);
|
1223
1229
|
|
1224
|
-
debug(`Generating fixed text for ${
|
1225
|
-
fixedResult = SourceCodeFixer.applyFixes(this.getSourceCode(), messages);
|
1230
|
+
debug(`Generating fixed text for ${debugTextDescription} (pass ${passNumber})`);
|
1231
|
+
fixedResult = SourceCodeFixer.applyFixes(this.getSourceCode(), messages, shouldFix);
|
1226
1232
|
|
1227
1233
|
// stop if there are any syntax errors.
|
1228
1234
|
// 'fixedResult.output' is a empty string.
|
@@ -1285,13 +1291,18 @@ const externalMethods = {
|
|
1285
1291
|
Object.keys(externalMethods).forEach(methodName => {
|
1286
1292
|
const exMethodName = externalMethods[methodName];
|
1287
1293
|
|
1288
|
-
//
|
1289
|
-
Linter.prototype
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1294
|
+
// Applies the SourceCode methods to the Linter prototype
|
1295
|
+
Object.defineProperty(Linter.prototype, methodName, {
|
1296
|
+
value() {
|
1297
|
+
if (this.sourceCode) {
|
1298
|
+
return this.sourceCode[exMethodName].apply(this.sourceCode, arguments);
|
1299
|
+
}
|
1300
|
+
return null;
|
1301
|
+
},
|
1302
|
+
configurable: true,
|
1303
|
+
writable: true,
|
1304
|
+
enumerable: false
|
1305
|
+
});
|
1295
1306
|
});
|
1296
1307
|
|
1297
1308
|
module.exports = Linter;
|
package/lib/rule-context.js
CHANGED
@@ -20,6 +20,7 @@ const PASSTHROUGHS = [
|
|
20
20
|
"getDeclaredVariables",
|
21
21
|
"getFilename",
|
22
22
|
"getScope",
|
23
|
+
"getSourceCode",
|
23
24
|
"markVariableAsUsed",
|
24
25
|
|
25
26
|
// DEPRECATED
|
@@ -58,7 +59,7 @@ const PASSTHROUGHS = [
|
|
58
59
|
*/
|
59
60
|
|
60
61
|
//------------------------------------------------------------------------------
|
61
|
-
//
|
62
|
+
// Module Definition
|
62
63
|
//------------------------------------------------------------------------------
|
63
64
|
|
64
65
|
/**
|
@@ -132,13 +133,13 @@ function getFix(descriptor, sourceCode) {
|
|
132
133
|
|
133
134
|
/**
|
134
135
|
* Rule context class
|
135
|
-
* Acts as an abstraction layer between rules and the main
|
136
|
+
* Acts as an abstraction layer between rules and the main linter object.
|
136
137
|
*/
|
137
138
|
class RuleContext {
|
138
139
|
|
139
140
|
/**
|
140
141
|
* @param {string} ruleId The ID of the rule using this object.
|
141
|
-
* @param {
|
142
|
+
* @param {Linter} linter The linter object.
|
142
143
|
* @param {number} severity The configured severity level of the rule.
|
143
144
|
* @param {Array} options The configuration information to be added to the rule.
|
144
145
|
* @param {Object} settings The configuration settings passed from the config file.
|
@@ -147,7 +148,7 @@ class RuleContext {
|
|
147
148
|
* @param {Object} meta The metadata of the rule
|
148
149
|
* @param {Object} parserServices The parser services for the rule.
|
149
150
|
*/
|
150
|
-
constructor(ruleId,
|
151
|
+
constructor(ruleId, linter, severity, options, settings, parserOptions, parserPath, meta, parserServices) {
|
151
152
|
|
152
153
|
// public.
|
153
154
|
this.id = ruleId;
|
@@ -161,22 +162,14 @@ class RuleContext {
|
|
161
162
|
this.parserServices = Object.freeze(Object.assign({}, parserServices));
|
162
163
|
|
163
164
|
// private.
|
164
|
-
this.
|
165
|
-
this.
|
165
|
+
this._linter = linter;
|
166
|
+
this._severity = severity;
|
166
167
|
|
167
168
|
Object.freeze(this);
|
168
169
|
}
|
169
170
|
|
170
171
|
/**
|
171
|
-
* Passthrough to
|
172
|
-
* @returns {SourceCode} The SourceCode object for the code.
|
173
|
-
*/
|
174
|
-
getSourceCode() {
|
175
|
-
return this.eslint.getSourceCode();
|
176
|
-
}
|
177
|
-
|
178
|
-
/**
|
179
|
-
* Passthrough to eslint.report() that automatically assigns the rule ID and severity.
|
172
|
+
* Passthrough to Linter#report() that automatically assigns the rule ID and severity.
|
180
173
|
* @param {ASTNode|MessageDescriptor} nodeOrDescriptor The AST node related to the message or a message
|
181
174
|
* descriptor.
|
182
175
|
* @param {Object=} location The location of the error.
|
@@ -192,38 +185,57 @@ class RuleContext {
|
|
192
185
|
const descriptor = nodeOrDescriptor;
|
193
186
|
const fix = getFix(descriptor, this.getSourceCode());
|
194
187
|
|
195
|
-
|
188
|
+
if (descriptor.loc) {
|
189
|
+
this._linter.report(
|
190
|
+
this.id,
|
191
|
+
this._severity,
|
192
|
+
descriptor.node,
|
193
|
+
descriptor.loc,
|
194
|
+
descriptor.message,
|
195
|
+
descriptor.data,
|
196
|
+
fix,
|
197
|
+
this.meta
|
198
|
+
);
|
199
|
+
} else {
|
200
|
+
this._linter.report(
|
201
|
+
this.id,
|
202
|
+
this._severity,
|
203
|
+
descriptor.node,
|
204
|
+
|
205
|
+
/* loc not provided */
|
206
|
+
descriptor.message,
|
207
|
+
descriptor.data,
|
208
|
+
fix,
|
209
|
+
this.meta
|
210
|
+
);
|
211
|
+
}
|
212
|
+
|
213
|
+
} else {
|
214
|
+
|
215
|
+
// old style call
|
216
|
+
this._linter.report(
|
196
217
|
this.id,
|
197
|
-
this.
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
fix,
|
218
|
+
this._severity,
|
219
|
+
nodeOrDescriptor,
|
220
|
+
location,
|
221
|
+
message,
|
222
|
+
opts,
|
203
223
|
this.meta
|
204
224
|
);
|
205
|
-
|
206
|
-
return;
|
207
225
|
}
|
208
|
-
|
209
|
-
// old style call
|
210
|
-
this.eslint.report(
|
211
|
-
this.id,
|
212
|
-
this.severity,
|
213
|
-
nodeOrDescriptor,
|
214
|
-
location,
|
215
|
-
message,
|
216
|
-
opts,
|
217
|
-
this.meta
|
218
|
-
);
|
219
226
|
}
|
220
227
|
}
|
221
228
|
|
222
|
-
// Copy over passthrough methods.
|
223
|
-
PASSTHROUGHS.forEach(
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
},
|
229
|
+
// Copy over passthrough methods.
|
230
|
+
PASSTHROUGHS.forEach(name => {
|
231
|
+
Object.defineProperty(RuleContext.prototype, name, {
|
232
|
+
value() {
|
233
|
+
return this._linter[name].apply(this._linter, arguments);
|
234
|
+
},
|
235
|
+
configurable: true,
|
236
|
+
writable: true,
|
237
|
+
enumerable: false
|
238
|
+
});
|
239
|
+
});
|
228
240
|
|
229
241
|
module.exports = RuleContext;
|
@@ -66,9 +66,12 @@ module.exports = {
|
|
66
66
|
*/
|
67
67
|
function fixParamsWithParenthesis(fixer) {
|
68
68
|
const paramToken = sourceCode.getTokenAfter(firstTokenOfParam);
|
69
|
-
|
69
|
+
|
70
|
+
// ES8 allows Trailing commas in function parameter lists and calls
|
71
|
+
// https://github.com/eslint/eslint/issues/8834
|
72
|
+
const closingParenToken = sourceCode.getTokenAfter(paramToken, astUtils.isClosingParenToken);
|
70
73
|
const asyncToken = isAsync ? sourceCode.getTokenBefore(firstTokenOfParam) : null;
|
71
|
-
const shouldAddSpaceForAsync = asyncToken && (asyncToken.
|
74
|
+
const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === firstTokenOfParam.range[0]);
|
72
75
|
|
73
76
|
return fixer.replaceTextRange([
|
74
77
|
firstTokenOfParam.range[0],
|
@@ -81,49 +81,49 @@ module.exports = {
|
|
81
81
|
category: "Stylistic Issues",
|
82
82
|
recommended: false
|
83
83
|
},
|
84
|
-
|
85
84
|
fixable: "code",
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
"never"
|
96
|
-
]
|
97
|
-
},
|
98
|
-
valueWithIgnore: {
|
99
|
-
anyOf: [
|
100
|
-
{
|
101
|
-
$ref: "#/defs/value"
|
102
|
-
},
|
103
|
-
{
|
104
|
-
enum: ["ignore"]
|
105
|
-
}
|
106
|
-
]
|
107
|
-
}
|
85
|
+
schema: {
|
86
|
+
definitions: {
|
87
|
+
value: {
|
88
|
+
enum: [
|
89
|
+
"always-multiline",
|
90
|
+
"always",
|
91
|
+
"never",
|
92
|
+
"only-multiline"
|
93
|
+
]
|
108
94
|
},
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
95
|
+
valueWithIgnore: {
|
96
|
+
enum: [
|
97
|
+
"always-multiline",
|
98
|
+
"always",
|
99
|
+
"ignore",
|
100
|
+
"never",
|
101
|
+
"only-multiline"
|
102
|
+
]
|
103
|
+
}
|
104
|
+
},
|
105
|
+
type: "array",
|
106
|
+
items: [
|
107
|
+
{
|
108
|
+
oneOf: [
|
109
|
+
{
|
110
|
+
$ref: "#/definitions/value"
|
121
111
|
},
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
112
|
+
{
|
113
|
+
type: "object",
|
114
|
+
properties: {
|
115
|
+
arrays: { $ref: "#/definitions/valueWithIgnore" },
|
116
|
+
objects: { $ref: "#/definitions/valueWithIgnore" },
|
117
|
+
imports: { $ref: "#/definitions/valueWithIgnore" },
|
118
|
+
exports: { $ref: "#/definitions/valueWithIgnore" },
|
119
|
+
functions: { $ref: "#/definitions/valueWithIgnore" }
|
120
|
+
},
|
121
|
+
additionalProperties: false
|
122
|
+
}
|
123
|
+
]
|
124
|
+
}
|
125
|
+
]
|
126
|
+
}
|
127
127
|
},
|
128
128
|
|
129
129
|
create(context) {
|
package/lib/rules/curly.js
CHANGED
@@ -238,7 +238,7 @@ module.exports = {
|
|
238
238
|
// `do while` expressions sometimes need a space to be inserted after `do`.
|
239
239
|
// e.g. `do{foo()} while (bar)` should be corrected to `do foo() while (bar)`
|
240
240
|
const needsPrecedingSpace = node.type === "DoWhileStatement" &&
|
241
|
-
sourceCode.getTokenBefore(bodyNode).
|
241
|
+
sourceCode.getTokenBefore(bodyNode).range[1] === bodyNode.range[0] &&
|
242
242
|
!astUtils.canTokensBeAdjacent("do", sourceCode.getFirstToken(bodyNode, { skip: 1 }));
|
243
243
|
|
244
244
|
const openingBracket = sourceCode.getFirstToken(bodyNode);
|
@@ -116,6 +116,15 @@ module.exports = {
|
|
116
116
|
return null;
|
117
117
|
}
|
118
118
|
|
119
|
+
if (node.object.type === "Identifier" && node.object.name === "let") {
|
120
|
+
|
121
|
+
/*
|
122
|
+
* A statement that starts with `let[` is parsed as a destructuring variable declaration, not
|
123
|
+
* a MemberExpression.
|
124
|
+
*/
|
125
|
+
return null;
|
126
|
+
}
|
127
|
+
|
119
128
|
return fixer.replaceTextRange(
|
120
129
|
[dot.range[0], node.property.range[1]],
|
121
130
|
`[${textAfterDot}"${node.property.name}"]`
|