eslint 6.1.0 → 6.3.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 +67 -0
- package/README.md +8 -4
- package/conf/config-schema.js +2 -0
- package/conf/default-cli-options.js +1 -1
- package/conf/environments.js +72 -15
- package/lib/cli-engine/config-array/config-array.js +13 -0
- package/lib/cli-engine/config-array/extracted-config.js +22 -1
- package/lib/cli-engine/config-array-factory.js +4 -0
- package/lib/cli-engine/formatters/stylish.js +2 -1
- package/lib/init/config-initializer.js +29 -0
- package/lib/init/npm-utils.js +10 -10
- package/lib/linter/apply-disable-directives.js +17 -9
- package/lib/linter/code-path-analysis/code-path-analyzer.js +1 -0
- package/lib/linter/linter.js +70 -17
- package/lib/options.js +1 -1
- package/lib/rules/accessor-pairs.js +195 -35
- package/lib/rules/class-methods-use-this.js +10 -3
- package/lib/rules/dot-notation.js +6 -2
- package/lib/rules/func-call-spacing.js +30 -20
- package/lib/rules/func-name-matching.js +1 -0
- package/lib/rules/func-names.js +4 -0
- package/lib/rules/function-call-argument-newline.js +120 -0
- package/lib/rules/function-paren-newline.js +36 -24
- package/lib/rules/indent.js +13 -2
- package/lib/rules/index.js +1 -0
- package/lib/rules/new-cap.js +2 -1
- package/lib/rules/no-dupe-keys.js +1 -1
- package/lib/rules/no-duplicate-case.js +10 -8
- package/lib/rules/no-extra-bind.js +1 -0
- package/lib/rules/no-extra-boolean-cast.js +54 -5
- package/lib/rules/no-extra-parens.js +62 -23
- package/lib/rules/no-mixed-operators.js +48 -13
- package/lib/rules/no-restricted-syntax.js +2 -2
- package/lib/rules/no-self-assign.js +11 -1
- package/lib/rules/no-unused-vars.js +1 -1
- package/lib/rules/prefer-template.js +1 -10
- package/lib/rules/sort-keys.js +11 -3
- package/lib/rules/utils/ast-utils.js +19 -2
- package/lib/rules/yoda.js +12 -3
- package/lib/shared/types.js +4 -0
- package/package.json +5 -5
package/lib/linter/linter.js
CHANGED
@@ -54,6 +54,11 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
|
|
54
54
|
/** @typedef {import("../shared/types").Processor} Processor */
|
55
55
|
/** @typedef {import("../shared/types").Rule} Rule */
|
56
56
|
|
57
|
+
/**
|
58
|
+
* @template T
|
59
|
+
* @typedef {{ [P in keyof T]-?: T[P] }} Required
|
60
|
+
*/
|
61
|
+
|
57
62
|
/**
|
58
63
|
* @typedef {Object} DisableDirective
|
59
64
|
* @property {("disable"|"enable"|"disable-line"|"disable-next-line")} type
|
@@ -79,7 +84,7 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
|
|
79
84
|
* @property {boolean} [disableFixes] if `true` then the linter doesn't make `fix`
|
80
85
|
* properties into the lint result.
|
81
86
|
* @property {string} [filename] the filename of the source code.
|
82
|
-
* @property {boolean} [reportUnusedDisableDirectives] Adds reported errors for
|
87
|
+
* @property {boolean | "off" | "warn" | "error"} [reportUnusedDisableDirectives] Adds reported errors for
|
83
88
|
* unused `eslint-disable` directives.
|
84
89
|
*/
|
85
90
|
|
@@ -103,6 +108,12 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
|
|
103
108
|
* whether fixes should be applied.
|
104
109
|
*/
|
105
110
|
|
111
|
+
/**
|
112
|
+
* @typedef {Object} InternalOptions
|
113
|
+
* @property {string | null} warnInlineConfig The config name what `noInlineConfig` setting came from. If `noInlineConfig` setting didn't exist, this is null. If this is a config name, then the linter warns directive comments.
|
114
|
+
* @property {"off" | "warn" | "error"} reportUnusedDisableDirectives (boolean values were normalized)
|
115
|
+
*/
|
116
|
+
|
106
117
|
//------------------------------------------------------------------------------
|
107
118
|
// Helpers
|
108
119
|
//------------------------------------------------------------------------------
|
@@ -198,14 +209,20 @@ function createMissingRuleMessage(ruleId) {
|
|
198
209
|
/**
|
199
210
|
* creates a linting problem
|
200
211
|
* @param {Object} options to create linting error
|
201
|
-
* @param {string} options.ruleId the ruleId to report
|
202
|
-
* @param {Object} options.loc the loc to report
|
203
|
-
* @param {string} options.message the error message to report
|
204
|
-
* @
|
212
|
+
* @param {string} [options.ruleId] the ruleId to report
|
213
|
+
* @param {Object} [options.loc] the loc to report
|
214
|
+
* @param {string} [options.message] the error message to report
|
215
|
+
* @param {string} [options.severity] the error message to report
|
216
|
+
* @returns {LintMessage} created problem, returns a missing-rule problem if only provided ruleId.
|
205
217
|
* @private
|
206
218
|
*/
|
207
219
|
function createLintingProblem(options) {
|
208
|
-
const {
|
220
|
+
const {
|
221
|
+
ruleId = null,
|
222
|
+
loc = DEFAULT_ERROR_LOC,
|
223
|
+
message = createMissingRuleMessage(options.ruleId),
|
224
|
+
severity = 2
|
225
|
+
} = options;
|
209
226
|
|
210
227
|
return {
|
211
228
|
ruleId,
|
@@ -214,7 +231,7 @@ function createLintingProblem(options) {
|
|
214
231
|
column: loc.start.column + 1,
|
215
232
|
endLine: loc.end.line,
|
216
233
|
endColumn: loc.end.column + 1,
|
217
|
-
severity
|
234
|
+
severity,
|
218
235
|
nodeType: null
|
219
236
|
};
|
220
237
|
}
|
@@ -257,10 +274,11 @@ function createDisableDirectives(options) {
|
|
257
274
|
* @param {string} filename The file being checked.
|
258
275
|
* @param {ASTNode} ast The top node of the AST.
|
259
276
|
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
277
|
+
* @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from.
|
260
278
|
* @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: Problem[], disableDirectives: DisableDirective[]}}
|
261
279
|
* A collection of the directive comments that were found, along with any problems that occurred when parsing
|
262
280
|
*/
|
263
|
-
function getDirectiveComments(filename, ast, ruleMapper) {
|
281
|
+
function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) {
|
264
282
|
const configuredRules = {};
|
265
283
|
const enabledGlobals = Object.create(null);
|
266
284
|
const exportedVariables = {};
|
@@ -269,16 +287,29 @@ function getDirectiveComments(filename, ast, ruleMapper) {
|
|
269
287
|
|
270
288
|
ast.comments.filter(token => token.type !== "Shebang").forEach(comment => {
|
271
289
|
const trimmedCommentText = comment.value.trim();
|
272
|
-
const match = /^(eslint(
|
290
|
+
const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(trimmedCommentText);
|
273
291
|
|
274
292
|
if (!match) {
|
275
293
|
return;
|
276
294
|
}
|
295
|
+
const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(match[1]);
|
296
|
+
|
297
|
+
if (warnInlineConfig && (lineCommentSupported || comment.type === "Block")) {
|
298
|
+
const kind = comment.type === "Block" ? `/*${match[1]}*/` : `//${match[1]}`;
|
299
|
+
|
300
|
+
problems.push(createLintingProblem({
|
301
|
+
ruleId: null,
|
302
|
+
message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`,
|
303
|
+
loc: comment.loc,
|
304
|
+
severity: 1
|
305
|
+
}));
|
306
|
+
return;
|
307
|
+
}
|
277
308
|
|
278
309
|
const directiveValue = trimmedCommentText.slice(match.index + match[1].length);
|
279
310
|
let directiveType = "";
|
280
311
|
|
281
|
-
if (
|
312
|
+
if (lineCommentSupported) {
|
282
313
|
if (comment.loc.start.line === comment.loc.end.line) {
|
283
314
|
directiveType = match[1].slice("eslint-".length);
|
284
315
|
} else {
|
@@ -441,17 +472,37 @@ function normalizeFilename(filename) {
|
|
441
472
|
return index === -1 ? filename : parts.slice(index).join(path.sep);
|
442
473
|
}
|
443
474
|
|
475
|
+
// eslint-disable-next-line valid-jsdoc
|
444
476
|
/**
|
445
477
|
* Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
|
446
478
|
* consistent shape.
|
447
479
|
* @param {VerifyOptions} providedOptions Options
|
448
|
-
* @
|
480
|
+
* @param {ConfigData} config Config.
|
481
|
+
* @returns {Required<VerifyOptions> & InternalOptions} Normalized options
|
449
482
|
*/
|
450
|
-
function normalizeVerifyOptions(providedOptions) {
|
483
|
+
function normalizeVerifyOptions(providedOptions, config) {
|
484
|
+
const disableInlineConfig = config.noInlineConfig === true;
|
485
|
+
const ignoreInlineConfig = providedOptions.allowInlineConfig === false;
|
486
|
+
const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig
|
487
|
+
? ` (${config.configNameOfNoInlineConfig})`
|
488
|
+
: "";
|
489
|
+
|
490
|
+
let reportUnusedDisableDirectives = providedOptions.reportUnusedDisableDirectives;
|
491
|
+
|
492
|
+
if (typeof reportUnusedDisableDirectives === "boolean") {
|
493
|
+
reportUnusedDisableDirectives = reportUnusedDisableDirectives ? "error" : "off";
|
494
|
+
}
|
495
|
+
if (typeof reportUnusedDisableDirectives !== "string") {
|
496
|
+
reportUnusedDisableDirectives = config.reportUnusedDisableDirectives ? "warn" : "off";
|
497
|
+
}
|
498
|
+
|
451
499
|
return {
|
452
500
|
filename: normalizeFilename(providedOptions.filename || "<input>"),
|
453
|
-
allowInlineConfig:
|
454
|
-
|
501
|
+
allowInlineConfig: !ignoreInlineConfig,
|
502
|
+
warnInlineConfig: disableInlineConfig && !ignoreInlineConfig
|
503
|
+
? `your config${configNameOfNoInlineConfig}`
|
504
|
+
: null,
|
505
|
+
reportUnusedDisableDirectives,
|
455
506
|
disableFixes: Boolean(providedOptions.disableFixes)
|
456
507
|
};
|
457
508
|
}
|
@@ -984,7 +1035,7 @@ class Linter {
|
|
984
1035
|
_verifyWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
|
985
1036
|
const slots = internalSlotsMap.get(this);
|
986
1037
|
const config = providedConfig || {};
|
987
|
-
const options = normalizeVerifyOptions(providedOptions);
|
1038
|
+
const options = normalizeVerifyOptions(providedOptions, config);
|
988
1039
|
let text;
|
989
1040
|
|
990
1041
|
// evaluate arguments
|
@@ -1019,7 +1070,9 @@ class Linter {
|
|
1019
1070
|
}
|
1020
1071
|
|
1021
1072
|
// search and apply "eslint-env *".
|
1022
|
-
const envInFile =
|
1073
|
+
const envInFile = options.allowInlineConfig && !options.warnInlineConfig
|
1074
|
+
? findEslintEnv(text)
|
1075
|
+
: {};
|
1023
1076
|
const resolvedEnvConfig = Object.assign({ builtin: true }, config.env, envInFile);
|
1024
1077
|
const enabledEnvs = Object.keys(resolvedEnvConfig)
|
1025
1078
|
.filter(envName => resolvedEnvConfig[envName])
|
@@ -1062,7 +1115,7 @@ class Linter {
|
|
1062
1115
|
|
1063
1116
|
const sourceCode = slots.lastSourceCode;
|
1064
1117
|
const commentDirectives = options.allowInlineConfig
|
1065
|
-
? getDirectiveComments(options.filename, sourceCode.ast, ruleId => getRule(slots, ruleId))
|
1118
|
+
? getDirectiveComments(options.filename, sourceCode.ast, ruleId => getRule(slots, ruleId), options.warnInlineConfig)
|
1066
1119
|
: { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
|
1067
1120
|
|
1068
1121
|
// augment global scope with declared global variables
|
package/lib/options.js
CHANGED
@@ -5,10 +5,87 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const astUtils = require("./utils/ast-utils");
|
13
|
+
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Typedefs
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Property name if it can be computed statically, otherwise the list of the tokens of the key node.
|
20
|
+
* @typedef {string|Token[]} Key
|
21
|
+
*/
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Accessor nodes with the same key.
|
25
|
+
* @typedef {Object} AccessorData
|
26
|
+
* @property {Key} key Accessor's key
|
27
|
+
* @property {ASTNode[]} getters List of getter nodes.
|
28
|
+
* @property {ASTNode[]} setters List of setter nodes.
|
29
|
+
*/
|
30
|
+
|
8
31
|
//------------------------------------------------------------------------------
|
9
32
|
// Helpers
|
10
33
|
//------------------------------------------------------------------------------
|
11
34
|
|
35
|
+
/**
|
36
|
+
* Checks whether or not the given lists represent the equal tokens in the same order.
|
37
|
+
* Tokens are compared by their properties, not by instance.
|
38
|
+
* @param {Token[]} left First list of tokens.
|
39
|
+
* @param {Token[]} right Second list of tokens.
|
40
|
+
* @returns {boolean} `true` if the lists have same tokens.
|
41
|
+
*/
|
42
|
+
function areEqualTokenLists(left, right) {
|
43
|
+
if (left.length !== right.length) {
|
44
|
+
return false;
|
45
|
+
}
|
46
|
+
|
47
|
+
for (let i = 0; i < left.length; i++) {
|
48
|
+
const leftToken = left[i],
|
49
|
+
rightToken = right[i];
|
50
|
+
|
51
|
+
if (leftToken.type !== rightToken.type || leftToken.value !== rightToken.value) {
|
52
|
+
return false;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
return true;
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Checks whether or not the given keys are equal.
|
61
|
+
* @param {Key} left First key.
|
62
|
+
* @param {Key} right Second key.
|
63
|
+
* @returns {boolean} `true` if the keys are equal.
|
64
|
+
*/
|
65
|
+
function areEqualKeys(left, right) {
|
66
|
+
if (typeof left === "string" && typeof right === "string") {
|
67
|
+
|
68
|
+
// Statically computed names.
|
69
|
+
return left === right;
|
70
|
+
}
|
71
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
72
|
+
|
73
|
+
// Token lists.
|
74
|
+
return areEqualTokenLists(left, right);
|
75
|
+
}
|
76
|
+
|
77
|
+
return false;
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Checks whether or not a given node is of an accessor kind ('get' or 'set').
|
82
|
+
* @param {ASTNode} node - A node to check.
|
83
|
+
* @returns {boolean} `true` if the node is of an accessor kind.
|
84
|
+
*/
|
85
|
+
function isAccessorKind(node) {
|
86
|
+
return node.kind === "get" || node.kind === "set";
|
87
|
+
}
|
88
|
+
|
12
89
|
/**
|
13
90
|
* Checks whether or not a given node is an `Identifier` node which was named a given name.
|
14
91
|
* @param {ASTNode} node - A node to check.
|
@@ -97,69 +174,152 @@ module.exports = {
|
|
97
174
|
}],
|
98
175
|
|
99
176
|
messages: {
|
100
|
-
|
101
|
-
|
177
|
+
missingGetterInPropertyDescriptor: "Getter is not present in property descriptor.",
|
178
|
+
missingSetterInPropertyDescriptor: "Setter is not present in property descriptor.",
|
179
|
+
missingGetterInObjectLiteral: "Getter is not present for {{ name }}.",
|
180
|
+
missingSetterInObjectLiteral: "Setter is not present for {{ name }}."
|
102
181
|
}
|
103
182
|
},
|
104
183
|
create(context) {
|
105
184
|
const config = context.options[0] || {};
|
106
185
|
const checkGetWithoutSet = config.getWithoutSet === true;
|
107
186
|
const checkSetWithoutGet = config.setWithoutGet !== false;
|
187
|
+
const sourceCode = context.getSourceCode();
|
108
188
|
|
109
189
|
/**
|
110
|
-
*
|
111
|
-
* @param {ASTNode} node The node to
|
190
|
+
* Reports the given node.
|
191
|
+
* @param {ASTNode} node The node to report.
|
192
|
+
* @param {string} messageKind "missingGetter" or "missingSetter".
|
112
193
|
* @returns {void}
|
113
194
|
* @private
|
114
195
|
*/
|
115
|
-
function
|
116
|
-
|
117
|
-
|
118
|
-
|
196
|
+
function report(node, messageKind) {
|
197
|
+
if (node.type === "Property") {
|
198
|
+
context.report({
|
199
|
+
node,
|
200
|
+
messageId: `${messageKind}InObjectLiteral`,
|
201
|
+
loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
|
202
|
+
data: { name: astUtils.getFunctionNameWithKind(node.value) }
|
203
|
+
});
|
204
|
+
} else {
|
205
|
+
context.report({
|
206
|
+
node,
|
207
|
+
messageId: `${messageKind}InPropertyDescriptor`
|
208
|
+
});
|
209
|
+
}
|
210
|
+
}
|
119
211
|
|
120
|
-
|
121
|
-
|
212
|
+
/**
|
213
|
+
* Reports each of the nodes in the given list using the same messageId.
|
214
|
+
* @param {ASTNode[]} nodes Nodes to report.
|
215
|
+
* @param {string} messageKind "missingGetter" or "missingSetter".
|
216
|
+
* @returns {void}
|
217
|
+
* @private
|
218
|
+
*/
|
219
|
+
function reportList(nodes, messageKind) {
|
220
|
+
for (const node of nodes) {
|
221
|
+
report(node, messageKind);
|
222
|
+
}
|
223
|
+
}
|
122
224
|
|
123
|
-
|
225
|
+
/**
|
226
|
+
* Creates a new `AccessorData` object for the given getter or setter node.
|
227
|
+
* @param {ASTNode} node A getter or setter node.
|
228
|
+
* @returns {AccessorData} New `AccessorData` object that contains the given node.
|
229
|
+
* @private
|
230
|
+
*/
|
231
|
+
function createAccessorData(node) {
|
232
|
+
const name = astUtils.getStaticPropertyName(node);
|
233
|
+
const key = (name !== null) ? name : sourceCode.getTokens(node.key);
|
124
234
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
}
|
235
|
+
return {
|
236
|
+
key,
|
237
|
+
getters: node.kind === "get" ? [node] : [],
|
238
|
+
setters: node.kind === "set" ? [node] : []
|
239
|
+
};
|
240
|
+
}
|
132
241
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
242
|
+
/**
|
243
|
+
* Merges the given `AccessorData` object into the given accessors list.
|
244
|
+
* @param {AccessorData[]} accessors The list to merge into.
|
245
|
+
* @param {AccessorData} accessorData The object to merge.
|
246
|
+
* @returns {AccessorData[]} The same instance with the merged object.
|
247
|
+
* @private
|
248
|
+
*/
|
249
|
+
function mergeAccessorData(accessors, accessorData) {
|
250
|
+
const equalKeyElement = accessors.find(a => areEqualKeys(a.key, accessorData.key));
|
137
251
|
|
138
|
-
|
139
|
-
|
140
|
-
|
252
|
+
if (equalKeyElement) {
|
253
|
+
equalKeyElement.getters.push(...accessorData.getters);
|
254
|
+
equalKeyElement.setters.push(...accessorData.setters);
|
255
|
+
} else {
|
256
|
+
accessors.push(accessorData);
|
257
|
+
}
|
141
258
|
|
142
|
-
|
259
|
+
return accessors;
|
260
|
+
}
|
143
261
|
|
144
|
-
|
145
|
-
|
262
|
+
/**
|
263
|
+
* Checks accessor pairs in the given list of nodes.
|
264
|
+
* @param {ASTNode[]} nodes The list to check.
|
265
|
+
* @returns {void}
|
266
|
+
* @private
|
267
|
+
*/
|
268
|
+
function checkList(nodes) {
|
269
|
+
const accessors = nodes
|
270
|
+
.filter(isAccessorKind)
|
271
|
+
.map(createAccessorData)
|
272
|
+
.reduce(mergeAccessorData, []);
|
146
273
|
|
147
|
-
|
148
|
-
|
274
|
+
for (const { getters, setters } of accessors) {
|
275
|
+
if (checkSetWithoutGet && setters.length && !getters.length) {
|
276
|
+
reportList(setters, "missingGetter");
|
277
|
+
}
|
278
|
+
if (checkGetWithoutSet && getters.length && !setters.length) {
|
279
|
+
reportList(getters, "missingSetter");
|
149
280
|
}
|
150
281
|
}
|
282
|
+
}
|
151
283
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
284
|
+
/**
|
285
|
+
* Checks accessor pairs in an object literal.
|
286
|
+
* @param {ASTNode} node `ObjectExpression` node to check.
|
287
|
+
* @returns {void}
|
288
|
+
* @private
|
289
|
+
*/
|
290
|
+
function checkObjectLiteral(node) {
|
291
|
+
checkList(node.properties.filter(p => p.type === "Property"));
|
292
|
+
}
|
293
|
+
|
294
|
+
/**
|
295
|
+
* Checks accessor pairs in a property descriptor.
|
296
|
+
* @param {ASTNode} node Property descriptor `ObjectExpression` node to check.
|
297
|
+
* @returns {void}
|
298
|
+
* @private
|
299
|
+
*/
|
300
|
+
function checkPropertyDescriptor(node) {
|
301
|
+
const namesToCheck = node.properties
|
302
|
+
.filter(p => p.type === "Property" && p.kind === "init" && !p.computed)
|
303
|
+
.map(({ key }) => key.name);
|
304
|
+
|
305
|
+
const hasGetter = namesToCheck.includes("get");
|
306
|
+
const hasSetter = namesToCheck.includes("set");
|
307
|
+
|
308
|
+
if (checkSetWithoutGet && hasSetter && !hasGetter) {
|
309
|
+
report(node, "missingGetter");
|
310
|
+
}
|
311
|
+
if (checkGetWithoutSet && hasGetter && !hasSetter) {
|
312
|
+
report(node, "missingSetter");
|
156
313
|
}
|
157
314
|
}
|
158
315
|
|
159
316
|
return {
|
160
317
|
ObjectExpression(node) {
|
161
318
|
if (checkSetWithoutGet || checkGetWithoutSet) {
|
162
|
-
|
319
|
+
checkObjectLiteral(node);
|
320
|
+
if (isPropertyDescriptor(node)) {
|
321
|
+
checkPropertyDescriptor(node);
|
322
|
+
}
|
163
323
|
}
|
164
324
|
}
|
165
325
|
};
|
@@ -5,6 +5,12 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const astUtils = require("./utils/ast-utils");
|
13
|
+
|
8
14
|
//------------------------------------------------------------------------------
|
9
15
|
// Rule Definition
|
10
16
|
//------------------------------------------------------------------------------
|
@@ -34,7 +40,7 @@ module.exports = {
|
|
34
40
|
}],
|
35
41
|
|
36
42
|
messages: {
|
37
|
-
missingThis: "Expected 'this' to be used by class
|
43
|
+
missingThis: "Expected 'this' to be used by class {{name}}."
|
38
44
|
}
|
39
45
|
},
|
40
46
|
create(context) {
|
@@ -70,7 +76,8 @@ module.exports = {
|
|
70
76
|
* @private
|
71
77
|
*/
|
72
78
|
function isIncludedInstanceMethod(node) {
|
73
|
-
return isInstanceMethod(node) &&
|
79
|
+
return isInstanceMethod(node) &&
|
80
|
+
(node.computed || !exceptMethods.has(node.key.name));
|
74
81
|
}
|
75
82
|
|
76
83
|
/**
|
@@ -89,7 +96,7 @@ module.exports = {
|
|
89
96
|
node,
|
90
97
|
messageId: "missingThis",
|
91
98
|
data: {
|
92
|
-
name: node
|
99
|
+
name: astUtils.getFunctionNameWithKind(node)
|
93
100
|
}
|
94
101
|
});
|
95
102
|
}
|
@@ -9,13 +9,16 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const astUtils = require("./utils/ast-utils");
|
12
|
+
const keywords = require("./utils/keywords");
|
12
13
|
|
13
14
|
//------------------------------------------------------------------------------
|
14
15
|
// Rule Definition
|
15
16
|
//------------------------------------------------------------------------------
|
16
17
|
|
17
18
|
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u;
|
18
|
-
|
19
|
+
|
20
|
+
// `null` literal must be handled separately.
|
21
|
+
const literalTypesToCheck = new Set(["string", "boolean"]);
|
19
22
|
|
20
23
|
module.exports = {
|
21
24
|
meta: {
|
@@ -115,7 +118,8 @@ module.exports = {
|
|
115
118
|
MemberExpression(node) {
|
116
119
|
if (
|
117
120
|
node.computed &&
|
118
|
-
node.property.type === "Literal"
|
121
|
+
node.property.type === "Literal" &&
|
122
|
+
(literalTypesToCheck.has(typeof node.property.value) || astUtils.isNullLiteral(node.property))
|
119
123
|
) {
|
120
124
|
checkComputedProperty(node, node.property.value);
|
121
125
|
}
|
@@ -78,21 +78,13 @@ module.exports = {
|
|
78
78
|
/**
|
79
79
|
* Check if open space is present in a function name
|
80
80
|
* @param {ASTNode} node node to evaluate
|
81
|
+
* @param {Token} leftToken The last token of the callee. This may be the closing parenthesis that encloses the callee.
|
82
|
+
* @param {Token} rightToken Tha first token of the arguments. this is the opening parenthesis that encloses the arguments.
|
81
83
|
* @returns {void}
|
82
84
|
* @private
|
83
85
|
*/
|
84
|
-
function checkSpacing(node) {
|
85
|
-
const
|
86
|
-
const lastCalleeToken = sourceCode.getLastToken(node.callee);
|
87
|
-
const parenToken = sourceCode.getFirstTokenBetween(lastCalleeToken, lastToken, astUtils.isOpeningParenToken);
|
88
|
-
const prevToken = parenToken && sourceCode.getTokenBefore(parenToken);
|
89
|
-
|
90
|
-
// Parens in NewExpression are optional
|
91
|
-
if (!(parenToken && parenToken.range[1] < node.range[1])) {
|
92
|
-
return;
|
93
|
-
}
|
94
|
-
|
95
|
-
const textBetweenTokens = text.slice(prevToken.range[1], parenToken.range[0]).replace(/\/\*.*?\*\//gu, "");
|
86
|
+
function checkSpacing(node, leftToken, rightToken) {
|
87
|
+
const textBetweenTokens = text.slice(leftToken.range[1], rightToken.range[0]).replace(/\/\*.*?\*\//gu, "");
|
96
88
|
const hasWhitespace = /\s/u.test(textBetweenTokens);
|
97
89
|
const hasNewline = hasWhitespace && astUtils.LINEBREAK_MATCHER.test(textBetweenTokens);
|
98
90
|
|
@@ -123,7 +115,7 @@ module.exports = {
|
|
123
115
|
if (never && hasWhitespace) {
|
124
116
|
context.report({
|
125
117
|
node,
|
126
|
-
loc:
|
118
|
+
loc: leftToken.loc.start,
|
127
119
|
messageId: "unexpected",
|
128
120
|
fix(fixer) {
|
129
121
|
|
@@ -132,7 +124,7 @@ module.exports = {
|
|
132
124
|
* https://github.com/eslint/eslint/issues/7787
|
133
125
|
*/
|
134
126
|
if (!hasNewline) {
|
135
|
-
return fixer.removeRange([
|
127
|
+
return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
|
136
128
|
}
|
137
129
|
|
138
130
|
return null;
|
@@ -141,27 +133,45 @@ module.exports = {
|
|
141
133
|
} else if (!never && !hasWhitespace) {
|
142
134
|
context.report({
|
143
135
|
node,
|
144
|
-
loc:
|
136
|
+
loc: leftToken.loc.start,
|
145
137
|
messageId: "missing",
|
146
138
|
fix(fixer) {
|
147
|
-
return fixer.insertTextBefore(
|
139
|
+
return fixer.insertTextBefore(rightToken, " ");
|
148
140
|
}
|
149
141
|
});
|
150
142
|
} else if (!never && !allowNewlines && hasNewline) {
|
151
143
|
context.report({
|
152
144
|
node,
|
153
|
-
loc:
|
145
|
+
loc: leftToken.loc.start,
|
154
146
|
messageId: "unexpected",
|
155
147
|
fix(fixer) {
|
156
|
-
return fixer.replaceTextRange([
|
148
|
+
return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " ");
|
157
149
|
}
|
158
150
|
});
|
159
151
|
}
|
160
152
|
}
|
161
153
|
|
162
154
|
return {
|
163
|
-
CallExpression
|
164
|
-
|
155
|
+
"CallExpression, NewExpression"(node) {
|
156
|
+
const lastToken = sourceCode.getLastToken(node);
|
157
|
+
const lastCalleeToken = sourceCode.getLastToken(node.callee);
|
158
|
+
const parenToken = sourceCode.getFirstTokenBetween(lastCalleeToken, lastToken, astUtils.isOpeningParenToken);
|
159
|
+
const prevToken = parenToken && sourceCode.getTokenBefore(parenToken);
|
160
|
+
|
161
|
+
// Parens in NewExpression are optional
|
162
|
+
if (!(parenToken && parenToken.range[1] < node.range[1])) {
|
163
|
+
return;
|
164
|
+
}
|
165
|
+
|
166
|
+
checkSpacing(node, prevToken, parenToken);
|
167
|
+
},
|
168
|
+
|
169
|
+
ImportExpression(node) {
|
170
|
+
const leftToken = sourceCode.getFirstToken(node);
|
171
|
+
const rightToken = sourceCode.getTokenAfter(leftToken);
|
172
|
+
|
173
|
+
checkSpacing(node, leftToken, rightToken);
|
174
|
+
}
|
165
175
|
};
|
166
176
|
|
167
177
|
}
|
package/lib/rules/func-names.js
CHANGED
@@ -69,6 +69,8 @@ module.exports = {
|
|
69
69
|
|
70
70
|
create(context) {
|
71
71
|
|
72
|
+
const sourceCode = context.getSourceCode();
|
73
|
+
|
72
74
|
/**
|
73
75
|
* Returns the config option for the given node.
|
74
76
|
* @param {ASTNode} node - A node to get the config for.
|
@@ -130,6 +132,7 @@ module.exports = {
|
|
130
132
|
context.report({
|
131
133
|
node,
|
132
134
|
messageId: "unnamed",
|
135
|
+
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
133
136
|
data: { name: astUtils.getFunctionNameWithKind(node) }
|
134
137
|
});
|
135
138
|
}
|
@@ -143,6 +146,7 @@ module.exports = {
|
|
143
146
|
context.report({
|
144
147
|
node,
|
145
148
|
messageId: "named",
|
149
|
+
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
146
150
|
data: { name: astUtils.getFunctionNameWithKind(node) }
|
147
151
|
});
|
148
152
|
}
|