eslint 3.16.0 → 3.18.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 +73 -0
- package/conf/eslint-recommended.js +2 -0
- package/lib/ast-utils.js +3 -67
- package/lib/code-path-analysis/code-path-analyzer.js +2 -7
- package/lib/code-path-analysis/debug-helpers.js +17 -16
- package/lib/config/config-file.js +68 -38
- package/lib/eslint.js +5 -5
- package/lib/formatters/stylish.js +5 -4
- package/lib/ignored-paths.js +6 -0
- package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
- package/lib/rules/array-callback-return.js +15 -5
- package/lib/rules/capitalized-comments.js +2 -1
- package/lib/rules/complexity.js +14 -8
- package/lib/rules/consistent-return.js +17 -10
- package/lib/rules/func-name-matching.js +18 -7
- package/lib/rules/func-names.js +20 -5
- package/lib/rules/keyword-spacing.js +19 -4
- package/lib/rules/line-comment-position.js +15 -5
- package/lib/rules/lines-around-comment.js +19 -0
- package/lib/rules/max-params.js +17 -4
- package/lib/rules/max-statements.js +11 -10
- package/lib/rules/no-compare-neg-zero.js +53 -0
- package/lib/rules/no-else-return.js +13 -1
- package/lib/rules/no-empty-function.js +9 -16
- package/lib/rules/no-extra-parens.js +64 -19
- package/lib/rules/no-extra-semi.js +13 -1
- package/lib/rules/no-global-assign.js +1 -1
- package/lib/rules/no-invalid-regexp.js +2 -1
- package/lib/rules/no-multiple-empty-lines.js +2 -4
- package/lib/rules/no-new-func.js +6 -8
- package/lib/rules/no-new.js +2 -6
- package/lib/rules/no-param-reassign.js +29 -6
- package/lib/rules/no-process-exit.js +2 -10
- package/lib/rules/no-restricted-properties.js +2 -0
- package/lib/rules/no-restricted-syntax.js +6 -22
- package/lib/rules/no-return-await.js +1 -1
- package/lib/rules/no-sync.js +8 -13
- package/lib/rules/no-unused-expressions.js +10 -1
- package/lib/rules/no-unused-vars.js +12 -12
- package/lib/rules/no-use-before-define.js +1 -1
- package/lib/rules/no-useless-escape.js +8 -2
- package/lib/rules/no-useless-return.js +13 -2
- package/lib/rules/nonblock-statement-body-position.js +114 -0
- package/lib/rules/object-shorthand.js +2 -1
- package/lib/rules/operator-assignment.js +1 -1
- package/lib/rules/padded-blocks.js +37 -28
- package/lib/rules/prefer-destructuring.js +1 -1
- package/lib/rules/semi.js +13 -1
- package/lib/rules/sort-vars.js +3 -5
- package/lib/rules/space-unary-ops.js +19 -1
- package/lib/rules/strict.js +8 -2
- package/lib/rules/yoda.js +2 -2
- package/lib/testers/rule-tester.js +44 -13
- package/lib/util/fix-tracker.js +121 -0
- package/lib/util/node-event-generator.js +274 -4
- package/lib/util/source-code-fixer.js +2 -2
- package/lib/util/source-code.js +99 -2
- package/lib/util/traverser.js +16 -25
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,76 @@
|
|
1
|
+
v3.18.0 - March 17, 2017
|
2
|
+
|
3
|
+
* 85f74ca Fix: broken code path of direct nested loops (fixes #8248) (#8274) (Toru Nagashima)
|
4
|
+
* a61c359 Fix: Ignore hidden folders when resolving globs (fixes #8259) (#8270) (Ian VanSchooten)
|
5
|
+
* 6f05546 Chore: convert StubModuleResolver in config tests to ES6 class (#8265) (Teddy Katz)
|
6
|
+
* 0c0fc31 Fix: false positive of no-extra-parens about spread and sequense (#8275) (Toru Nagashima)
|
7
|
+
* e104973 Docs: remove self-reference in no-restricted-syntax docs (#8277) (Vitor Balocco)
|
8
|
+
* 23eca51 Update: Add allowTaggedTemplates to no-unused-expressions (fixes #7632) (#8253) (Kevin Partington)
|
9
|
+
* f9ede3f Upgrade: doctrine to 2.0.0 (#8269) (alberto)
|
10
|
+
* 1b678a6 New: allow rules to listen for AST selectors (fixes #5407) (#7833) (Teddy Katz)
|
11
|
+
* 63ca0c5 Chore: use precalculated counts in stylish formatter (#8251) (alberto)
|
12
|
+
* 47c3171 Fix: typo in console.error (#8258) (Jan Peer Stöcklmair)
|
13
|
+
* e74ed6d Chore: convert Traverser to ES6 class (refs #7849) (#8232) (Teddy Katz)
|
14
|
+
* 13eead9 Fix: sort-vars crash on mixed destructuring declarations (#8245) (Teddy Katz)
|
15
|
+
* 133f489 Fix: func-name-matching crash on destructuring assignment to functions (#8247) (Teddy Katz)
|
16
|
+
* a34b9c4 Fix: func-name-matching crash on non-string literal computed keys (#8246) (Teddy Katz)
|
17
|
+
* 7276e6d Docs: remove unneeded semicolons in arrow-parens.md (#8249) (Dmitry Gershun)
|
18
|
+
* 8c40a25 concat-stream known to be vulnerable prior 1.5.2 (#8228) (Samuel)
|
19
|
+
* 149c055 Upgrade: mock-fs to v4.2.0 (fixes #8194) (#8243) (Teddy Katz)
|
20
|
+
* a83bff9 Build: remove unneeded json config in demo (fixes #8237) (#8242) (alberto)
|
21
|
+
* df12137 Docs: fix typos (#8235) (Gyandeep Singh)
|
22
|
+
* b5e9788 Chore: rename no-extra-parens methods (#8225) (Vitor Balocco)
|
23
|
+
* 7f8afe6 Update: no-extra-parens overlooked spread and superClass (fixes #8175) (#8209) (Toru Nagashima)
|
24
|
+
* ce6ff56 Docs: set recommended true for no-global-assign (fixes #8215) (#8218) (BinYi LIU)
|
25
|
+
* 5b5c236 Fix: wrong comment when module not found in config (fixes #8192) (#8196) (alberto)
|
26
|
+
|
27
|
+
v3.17.1 - March 6, 2017
|
28
|
+
|
29
|
+
* f8c8e6e Build: change mock-fs path without SSH (fixes #8207) (#8208) (Toru Nagashima)
|
30
|
+
* f713f11 Fix: nonblock-statement-body-position multiline error (fixes #8202) (#8203) (Teddy Katz)
|
31
|
+
* 41e3d9c Fix: `operator-assignment` with parenthesized expression (fixes #8190) (#8197) (alberto)
|
32
|
+
* 5e3bca7 Chore: add eslint-plugin-eslint-plugin (#8198) (Teddy Katz)
|
33
|
+
* 580da36 Chore: add missing `output` property to tests (#8195) (alberto)
|
34
|
+
|
35
|
+
v3.17.0 - March 3, 2017
|
36
|
+
|
37
|
+
* 4fdf6d7 Update: deprecate `applyDefaultPatterns` in `line-comment-position` (#8183) (alberto)
|
38
|
+
* 25e5817 Fix: Don't autofix `+ +a` to `++a` in space-unary-ops (#8176) (Alan Pierce)
|
39
|
+
* a6ce8f9 Build: Sort rules before dumping them to doc files (#8154) (Danny Andrews)
|
40
|
+
* 0af9057 Chore: Upgrade to a patched version of mock-fs (fixes #8177) (#8188) (Teddy Katz)
|
41
|
+
* bf4d8cf Update: ignore eslint comments in lines-arount-comment (fixes #4345) (#8155) (alberto)
|
42
|
+
* dad20ad New: add SourceCode#getLocFromIndex and #getIndexFromLoc (fixes #8073) (#8158) (Teddy Katz)
|
43
|
+
* 18a519f Update: let RuleTester cases assert that no autofix occurs (fixes #8157) (#8163) (Teddy Katz)
|
44
|
+
* a30eb8d Docs: improve documentation for RuleTester cases (#8162) (Teddy Katz)
|
45
|
+
* a78ec9f Chore: upgrade `coveralls` to ^2.11.16 (#8161) (alberto)
|
46
|
+
* d02bd11 Fix: padded-blocks autofix problems with comments (#8149) (alberto)
|
47
|
+
* 9994889 Docs: Add missing space to `create` in `no-use-before-define` (#8166) (Justin Anastos)
|
48
|
+
* 4d542ba Docs: Remove unneeded statement about autofix (#8164) (alberto)
|
49
|
+
* 20daea5 New: no-compare-neg-zero rule (#8091) (薛定谔的猫)
|
50
|
+
* 4d35a81 Fix: Add a utility to avoid autofix conflicts (fixes #7928, fixes #8026) (#8067) (Alan Pierce)
|
51
|
+
* 287e882 New: nonblock-statement-body-position rule (fixes #6067) (#8108) (Teddy Katz)
|
52
|
+
* 7f1f4e5 Chore: remove unneeded devDeps `linefix` and `gh-got` (#8160) (alberto)
|
53
|
+
* ca1694b Update: ignore negative ranges in fixes (#8133) (alberto)
|
54
|
+
* 163d751 Docs: `lines-around-comment` doesn't disallow empty lines (#8151) (alberto)
|
55
|
+
* 1c84922 Chore: upgrade eslint-plugin-node (#8156) (alberto)
|
56
|
+
* 1ee5c27 Fix: Make RuleTester handle empty-string cases gracefully (fixes #8142) (#8143) (Teddy Katz)
|
57
|
+
* 044bc10 Docs: Add details about "--fix" option for "sort-imports" rule (#8077) (Olivier Audard)
|
58
|
+
* 3fec54a Add option to ignore property in no-param-reassign (#8087) (Christian Bundy)
|
59
|
+
* 4e52cfc Fix: Improve keyword-spacing typescript support (fixes #8110) (#8111) (Reyad Attiyat)
|
60
|
+
* 7ff42e8 New: Allow regexes in RuleTester (fixes #7837) (#8115) (Daniel Lo Nigro)
|
61
|
+
* cbd7ded Build: display rules’ meta data in their docs (fixes #5774) (#8127) (Wilson Kurniawan)
|
62
|
+
* da8e8af Update: include function name in report message if possible (fixes #7260) (#8058) (Dieter Luypaert)
|
63
|
+
* 8f91e32 Fix: `ignoreRestSiblings` option didn't cover arguments (fixes #8119) (#8120) (Toru Nagashima)
|
64
|
+
|
65
|
+
v3.16.1 - February 22, 2017
|
66
|
+
|
67
|
+
* ff8a80c Fix: duplicated autofix output for inverted fix ranges (fixes #8116) (#8117) (Teddy Katz)
|
68
|
+
* a421897 Docs: fix typo in arrow-parens.md (#8132) (Will Chen)
|
69
|
+
* 22d7fbf Chore: fix invalid redeclared variables in tests (#8130) (Teddy Katz)
|
70
|
+
* 8d95598 Chore: fix output assertion typos in rule tests (#8129) (Teddy Katz)
|
71
|
+
* 9fa2559 Docs: Add missing quotes in key-spacing rule (#8121) (Glenn Reyes)
|
72
|
+
* f3a6ced Build: package.json update for eslint-config-eslint release (ESLint Jenkins)
|
73
|
+
|
1
74
|
v3.16.0 - February 20, 2017
|
2
75
|
|
3
76
|
* d89d0b4 Update: fix quotes false negative for string literals as template tags (#8107) (Teddy Katz)
|
@@ -84,6 +84,7 @@ module.exports = {
|
|
84
84
|
"no-case-declarations": "error",
|
85
85
|
"no-catch-shadow": "off",
|
86
86
|
"no-class-assign": "error",
|
87
|
+
"no-compare-neg-zero": "off",
|
87
88
|
"no-cond-assign": "error",
|
88
89
|
"no-confusing-arrow": "off",
|
89
90
|
"no-console": "error",
|
@@ -209,6 +210,7 @@ module.exports = {
|
|
209
210
|
"no-warning-comments": "off",
|
210
211
|
"no-whitespace-before-property": "off",
|
211
212
|
"no-with": "off",
|
213
|
+
"nonblock-statement-body-position": "off",
|
212
214
|
"object-curly-newline": "off",
|
213
215
|
"object-curly-spacing": ["off", "never"],
|
214
216
|
"object-property-newline": "off",
|
package/lib/ast-utils.js
CHANGED
@@ -10,7 +10,6 @@
|
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
12
|
const esutils = require("esutils");
|
13
|
-
const lodash = require("lodash");
|
14
13
|
|
15
14
|
//------------------------------------------------------------------------------
|
16
15
|
// Helpers
|
@@ -24,6 +23,8 @@ const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/;
|
|
24
23
|
const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/;
|
25
24
|
const thisTagPattern = /^[\s*]*@this/m;
|
26
25
|
|
26
|
+
|
27
|
+
const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/;
|
27
28
|
const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
|
28
29
|
const LINEBREAK_MATCHER = /\r\n|[\r\n\u2028\u2029]/;
|
29
30
|
|
@@ -403,45 +404,12 @@ function createGlobalLinebreakMatcher() {
|
|
403
404
|
return new RegExp(LINEBREAK_MATCHER.source, "g");
|
404
405
|
}
|
405
406
|
|
406
|
-
const lineIndexCache = new WeakMap();
|
407
|
-
|
408
|
-
/**
|
409
|
-
* Gets the range index for the first character in each of the lines of `sourceCode`.
|
410
|
-
* @param {SourceCode} sourceCode A sourceCode object
|
411
|
-
* @returns {number[]} The indices of the first characters in the each of the lines of the code
|
412
|
-
*/
|
413
|
-
function getLineIndices(sourceCode) {
|
414
|
-
|
415
|
-
if (!lineIndexCache.has(sourceCode)) {
|
416
|
-
const lineIndices = [0];
|
417
|
-
const lineEndingPattern = createGlobalLinebreakMatcher();
|
418
|
-
let match;
|
419
|
-
|
420
|
-
/*
|
421
|
-
* Previously, this function was implemented using a regex that
|
422
|
-
* matched a sequence of non-linebreak characters followed by a
|
423
|
-
* linebreak, then adding the lengths of the matches. However,
|
424
|
-
* this caused a catastrophic backtracking issue when the end
|
425
|
-
* of a file contained a large number of non-newline characters.
|
426
|
-
* To avoid this, the current implementation just matches newlines
|
427
|
-
* and uses match.index to get the correct line start indices.
|
428
|
-
*/
|
429
|
-
|
430
|
-
while ((match = lineEndingPattern.exec(sourceCode.text))) {
|
431
|
-
lineIndices.push(match.index + match[0].length);
|
432
|
-
}
|
433
|
-
|
434
|
-
// Store the sourceCode object in a WeakMap to avoid iterating over all of the lines every time a sourceCode object is passed in.
|
435
|
-
lineIndexCache.set(sourceCode, lineIndices);
|
436
|
-
}
|
437
|
-
return lineIndexCache.get(sourceCode);
|
438
|
-
}
|
439
|
-
|
440
407
|
//------------------------------------------------------------------------------
|
441
408
|
// Public Interface
|
442
409
|
//------------------------------------------------------------------------------
|
443
410
|
|
444
411
|
module.exports = {
|
412
|
+
COMMENTS_IGNORE_PATTERN,
|
445
413
|
LINEBREAKS,
|
446
414
|
LINEBREAK_MATCHER,
|
447
415
|
STATEMENT_LIST_PARENTS,
|
@@ -1207,38 +1175,6 @@ module.exports = {
|
|
1207
1175
|
};
|
1208
1176
|
},
|
1209
1177
|
|
1210
|
-
/*
|
1211
|
-
* Converts a range index into a (line, column) pair.
|
1212
|
-
* @param {SourceCode} sourceCode A SourceCode object
|
1213
|
-
* @param {number} rangeIndex The range index of a character in a file
|
1214
|
-
* @returns {Object} A {line, column} location object with a 0-indexed column
|
1215
|
-
*/
|
1216
|
-
getLocationFromRangeIndex(sourceCode, rangeIndex) {
|
1217
|
-
const lineIndices = getLineIndices(sourceCode);
|
1218
|
-
|
1219
|
-
/*
|
1220
|
-
* lineIndices is a sorted list of indices of the first character of each line.
|
1221
|
-
* To figure out which line rangeIndex is on, determine the last index at which rangeIndex could
|
1222
|
-
* be inserted into lineIndices to keep the list sorted.
|
1223
|
-
*/
|
1224
|
-
const lineNumber = lodash.sortedLastIndex(lineIndices, rangeIndex);
|
1225
|
-
|
1226
|
-
return { line: lineNumber, column: rangeIndex - lineIndices[lineNumber - 1] };
|
1227
|
-
|
1228
|
-
},
|
1229
|
-
|
1230
|
-
/**
|
1231
|
-
* Converts a (line, column) pair into a range index.
|
1232
|
-
* @param {SourceCode} sourceCode A SourceCode object
|
1233
|
-
* @param {Object} loc A line/column location
|
1234
|
-
* @param {number} loc.line The line number of the location (1-indexed)
|
1235
|
-
* @param {number} loc.column The column number of the location (0-indexed)
|
1236
|
-
* @returns {number} The range index of the location in the file.
|
1237
|
-
*/
|
1238
|
-
getRangeIndexFromLocation(sourceCode, loc) {
|
1239
|
-
return getLineIndices(sourceCode)[loc.line - 1] + loc.column;
|
1240
|
-
},
|
1241
|
-
|
1242
1178
|
/**
|
1243
1179
|
* Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
|
1244
1180
|
* surrounding the node.
|
@@ -512,13 +512,8 @@ function processCodePathToExit(analyzer, node) {
|
|
512
512
|
break;
|
513
513
|
}
|
514
514
|
|
515
|
-
|
516
|
-
|
517
|
-
* the node type is the same as the parent node type.
|
518
|
-
*/
|
519
|
-
if (!dontForward && (!node.parent || node.type !== node.parent.type)) {
|
520
|
-
|
521
|
-
// Emits onCodePathSegmentStart events if updated.
|
515
|
+
// Emits onCodePathSegmentStart events if updated.
|
516
|
+
if (!dontForward) {
|
522
517
|
forwardCurrentToHead(analyzer, node);
|
523
518
|
}
|
524
519
|
debug.dumpState(node, state, true);
|
@@ -107,22 +107,23 @@ module.exports = {
|
|
107
107
|
text += "style=\"rounded,dashed,filled\",fillcolor=\"#FF9800\",label=\"<<unreachable>>\\n";
|
108
108
|
}
|
109
109
|
|
110
|
-
if (segment.internal.nodes.length > 0) {
|
111
|
-
text +=
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
110
|
+
if (segment.internal.nodes.length > 0 || segment.internal.exitNodes.length > 0) {
|
111
|
+
text += [].concat(
|
112
|
+
segment.internal.nodes.map(node => {
|
113
|
+
switch (node.type) {
|
114
|
+
case "Identifier": return `${node.type} (${node.name})`;
|
115
|
+
case "Literal": return `${node.type} (${node.value})`;
|
116
|
+
default: return node.type;
|
117
|
+
}
|
118
|
+
}),
|
119
|
+
segment.internal.exitNodes.map(node => {
|
120
|
+
switch (node.type) {
|
121
|
+
case "Identifier": return `${node.type}:exit (${node.name})`;
|
122
|
+
case "Literal": return `${node.type}:exit (${node.value})`;
|
123
|
+
default: return `${node.type}:exit`;
|
124
|
+
}
|
125
|
+
})
|
126
|
+
).join("\\n");
|
126
127
|
} else {
|
127
128
|
text += "????";
|
128
129
|
}
|
@@ -183,6 +183,22 @@ function loadPackageJSONConfigFile(filePath) {
|
|
183
183
|
}
|
184
184
|
}
|
185
185
|
|
186
|
+
/**
|
187
|
+
* Creates an error to notify about a missing config to extend from.
|
188
|
+
* @param {string} configName The name of the missing config.
|
189
|
+
* @returns {Error} The error object to throw
|
190
|
+
* @private
|
191
|
+
*/
|
192
|
+
function configMissingError(configName) {
|
193
|
+
const error = new Error(`Failed to load config "${configName}" to extend from.`);
|
194
|
+
|
195
|
+
error.messageTemplate = "extend-config-missing";
|
196
|
+
error.messageData = {
|
197
|
+
configName
|
198
|
+
};
|
199
|
+
return error;
|
200
|
+
}
|
201
|
+
|
186
202
|
/**
|
187
203
|
* Loads a configuration file regardless of the source. Inspects the file path
|
188
204
|
* to determine the correctly way to load the config file.
|
@@ -199,6 +215,9 @@ function loadConfigFile(file) {
|
|
199
215
|
config = loadJSConfigFile(filePath);
|
200
216
|
if (file.configName) {
|
201
217
|
config = config.configs[file.configName];
|
218
|
+
if (!config) {
|
219
|
+
throw configMissingError(file.configFullName);
|
220
|
+
}
|
202
221
|
}
|
203
222
|
break;
|
204
223
|
|
@@ -340,6 +359,33 @@ function getLookupPath(configFilePath) {
|
|
340
359
|
return path.join(basedir, "node_modules");
|
341
360
|
}
|
342
361
|
|
362
|
+
/**
|
363
|
+
* Resolves a eslint core config path
|
364
|
+
* @param {string} name The eslint config name.
|
365
|
+
* @returns {string} The resolved path of the config.
|
366
|
+
* @private
|
367
|
+
*/
|
368
|
+
function getEslintCoreConfigPath(name) {
|
369
|
+
if (name === "eslint:recommended") {
|
370
|
+
|
371
|
+
/*
|
372
|
+
* Add an explicit substitution for eslint:recommended to
|
373
|
+
* conf/eslint-recommended.js.
|
374
|
+
*/
|
375
|
+
return path.resolve(__dirname, "../../conf/eslint-recommended.js");
|
376
|
+
}
|
377
|
+
|
378
|
+
if (name === "eslint:all") {
|
379
|
+
|
380
|
+
/*
|
381
|
+
* Add an explicit substitution for eslint:all to conf/eslint-all.js
|
382
|
+
*/
|
383
|
+
return path.resolve(__dirname, "../../conf/eslint-all.js");
|
384
|
+
}
|
385
|
+
|
386
|
+
throw configMissingError(name);
|
387
|
+
}
|
388
|
+
|
343
389
|
/**
|
344
390
|
* Applies values from the "extends" field in a configuration file.
|
345
391
|
* @param {Object} config The configuration information.
|
@@ -360,43 +406,23 @@ function applyExtends(config, filePath, relativeTo) {
|
|
360
406
|
|
361
407
|
// Make the last element in an array take the highest precedence
|
362
408
|
config = configExtends.reduceRight((previousValue, parentPath) => {
|
363
|
-
|
364
|
-
if (parentPath === "eslint:recommended") {
|
365
|
-
|
366
|
-
/*
|
367
|
-
* Add an explicit substitution for eslint:recommended to
|
368
|
-
* conf/eslint-recommended.js.
|
369
|
-
*/
|
370
|
-
parentPath = path.resolve(__dirname, "../../conf/eslint-recommended.js");
|
371
|
-
} else if (parentPath === "eslint:all") {
|
372
|
-
|
373
|
-
/*
|
374
|
-
* Add an explicit substitution for eslint:all to conf/eslint-all.js
|
375
|
-
*/
|
376
|
-
parentPath = path.resolve(__dirname, "../../conf/eslint-all.js");
|
377
|
-
} else if (isFilePath(parentPath)) {
|
378
|
-
|
379
|
-
/*
|
380
|
-
* If the `extends` path is relative, use the directory of the current configuration
|
381
|
-
* file as the reference point. Otherwise, use as-is.
|
382
|
-
*/
|
383
|
-
parentPath = (!path.isAbsolute(parentPath)
|
384
|
-
? path.join(relativeTo || path.dirname(filePath), parentPath)
|
385
|
-
: parentPath
|
386
|
-
);
|
387
|
-
}
|
388
|
-
|
389
409
|
try {
|
410
|
+
if (parentPath.startsWith("eslint:")) {
|
411
|
+
parentPath = getEslintCoreConfigPath(parentPath);
|
412
|
+
} else if (isFilePath(parentPath)) {
|
413
|
+
|
414
|
+
/*
|
415
|
+
* If the `extends` path is relative, use the directory of the current configuration
|
416
|
+
* file as the reference point. Otherwise, use as-is.
|
417
|
+
*/
|
418
|
+
parentPath = (path.isAbsolute(parentPath)
|
419
|
+
? parentPath
|
420
|
+
: path.join(relativeTo || path.dirname(filePath), parentPath)
|
421
|
+
);
|
422
|
+
}
|
390
423
|
debug(`Loading ${parentPath}`);
|
391
424
|
return ConfigOps.merge(load(parentPath, false, relativeTo), previousValue);
|
392
425
|
} catch (e) {
|
393
|
-
if (parentPath.indexOf("plugin:") === 0 || parentPath.indexOf("eslint:") === 0) {
|
394
|
-
e.message = `Failed to load config "${parentPath}" to extend from.`;
|
395
|
-
e.messageTemplate = "extend-config-missing";
|
396
|
-
e.messageData = {
|
397
|
-
configName: parentPath
|
398
|
-
};
|
399
|
-
}
|
400
426
|
|
401
427
|
/*
|
402
428
|
* If the file referenced by `extends` failed to load, add the path
|
@@ -462,7 +488,10 @@ function normalizePackageName(name, prefix) {
|
|
462
488
|
* or package name.
|
463
489
|
* @param {string} filePath The filepath to resolve.
|
464
490
|
* @param {string} [relativeTo] The path to resolve relative to.
|
465
|
-
* @returns {Object}
|
491
|
+
* @returns {Object} An object containing 3 properties:
|
492
|
+
* - 'filePath' (required) the resolved path that can be used directly to load the configuration.
|
493
|
+
* - 'configName' the name of the configuration inside the plugin.
|
494
|
+
* - 'configFullName' the name of the configuration as used in the eslint config (e.g. 'plugin:node/recommended').
|
466
495
|
* @private
|
467
496
|
*/
|
468
497
|
function resolve(filePath, relativeTo) {
|
@@ -471,14 +500,15 @@ function resolve(filePath, relativeTo) {
|
|
471
500
|
}
|
472
501
|
let normalizedPackageName;
|
473
502
|
|
474
|
-
if (filePath.
|
475
|
-
const
|
503
|
+
if (filePath.startsWith("plugin:")) {
|
504
|
+
const configFullName = filePath;
|
505
|
+
const pluginName = filePath.substr(7, filePath.lastIndexOf("/") - 7);
|
476
506
|
const configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1);
|
477
507
|
|
478
|
-
normalizedPackageName = normalizePackageName(
|
508
|
+
normalizedPackageName = normalizePackageName(pluginName, "eslint-plugin");
|
479
509
|
debug(`Attempting to resolve ${normalizedPackageName}`);
|
480
510
|
filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
|
481
|
-
return { filePath, configName };
|
511
|
+
return { filePath, configName, configFullName };
|
482
512
|
}
|
483
513
|
normalizedPackageName = normalizePackageName(filePath, "eslint-config");
|
484
514
|
debug(`Attempting to resolve ${normalizedPackageName}`);
|
package/lib/eslint.js
CHANGED
@@ -867,11 +867,11 @@ module.exports = (function() {
|
|
867
867
|
const rule = ruleCreator.create ? ruleCreator.create(ruleContext)
|
868
868
|
: ruleCreator(ruleContext);
|
869
869
|
|
870
|
-
// add all the
|
871
|
-
Object.keys(rule).forEach(
|
872
|
-
api.on(
|
873
|
-
? timing.time(key, rule[
|
874
|
-
: rule[
|
870
|
+
// add all the selectors from the rule as listeners
|
871
|
+
Object.keys(rule).forEach(selector => {
|
872
|
+
api.on(selector, timing.enabled
|
873
|
+
? timing.time(key, rule[selector])
|
874
|
+
: rule[selector]
|
875
875
|
);
|
876
876
|
});
|
877
877
|
} catch (ex) {
|
@@ -28,7 +28,6 @@ function pluralize(word, count) {
|
|
28
28
|
module.exports = function(results) {
|
29
29
|
|
30
30
|
let output = "\n",
|
31
|
-
total = 0,
|
32
31
|
errors = 0,
|
33
32
|
warnings = 0,
|
34
33
|
summaryColor = "yellow";
|
@@ -40,7 +39,9 @@ module.exports = function(results) {
|
|
40
39
|
return;
|
41
40
|
}
|
42
41
|
|
43
|
-
|
42
|
+
errors += result.errorCount;
|
43
|
+
warnings += result.warningCount;
|
44
|
+
|
44
45
|
output += `${chalk.underline(result.filePath)}\n`;
|
45
46
|
|
46
47
|
output += `${table(
|
@@ -50,10 +51,8 @@ module.exports = function(results) {
|
|
50
51
|
if (message.fatal || message.severity === 2) {
|
51
52
|
messageType = chalk.red("error");
|
52
53
|
summaryColor = "red";
|
53
|
-
errors++;
|
54
54
|
} else {
|
55
55
|
messageType = chalk.yellow("warning");
|
56
|
-
warnings++;
|
57
56
|
}
|
58
57
|
|
59
58
|
return [
|
@@ -74,6 +73,8 @@ module.exports = function(results) {
|
|
74
73
|
).split("\n").map(el => el.replace(/(\d+)\s+(\d+)/, (m, p1, p2) => chalk.dim(`${p1}:${p2}`))).join("\n")}\n\n`;
|
75
74
|
});
|
76
75
|
|
76
|
+
const total = errors + warnings;
|
77
|
+
|
77
78
|
if (total > 0) {
|
78
79
|
output += chalk[summaryColor].bold([
|
79
80
|
"\u2716 ", total, pluralize(" problem", total),
|
package/lib/ignored-paths.js
CHANGED
@@ -201,6 +201,12 @@ class IgnoredPaths {
|
|
201
201
|
|
202
202
|
const ig = ignore().add(DEFAULT_IGNORE_DIRS);
|
203
203
|
|
204
|
+
if (this.options.dotfiles !== true) {
|
205
|
+
|
206
|
+
// Ignore hidden folders. (This cannot be ".*", or else it's not possible to unignore hidden files)
|
207
|
+
ig.add([".*/*", "!../"]);
|
208
|
+
}
|
209
|
+
|
204
210
|
if (this.options.ignore) {
|
205
211
|
ig.add(this.ig.custom);
|
206
212
|
}
|
@@ -94,16 +94,6 @@ function hasMetaSchema(metaPropertyNode) {
|
|
94
94
|
return getPropertyFromObject("schema", metaPropertyNode.value);
|
95
95
|
}
|
96
96
|
|
97
|
-
/**
|
98
|
-
* Whether this `meta` ObjectExpression has a `fixable` property defined or not.
|
99
|
-
*
|
100
|
-
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
|
101
|
-
* @returns {boolean} `true` if a `fixable` property exists.
|
102
|
-
*/
|
103
|
-
function hasMetaFixable(metaPropertyNode) {
|
104
|
-
return getPropertyFromObject("fixable", metaPropertyNode.value);
|
105
|
-
}
|
106
|
-
|
107
97
|
/**
|
108
98
|
* Checks the validity of the meta definition of this rule and reports any errors found.
|
109
99
|
*
|
@@ -112,7 +102,7 @@ function hasMetaFixable(metaPropertyNode) {
|
|
112
102
|
* @param {boolean} ruleIsFixable whether the rule is fixable or not.
|
113
103
|
* @returns {void}
|
114
104
|
*/
|
115
|
-
function checkMetaValidity(context, exportsNode
|
105
|
+
function checkMetaValidity(context, exportsNode) {
|
116
106
|
const metaProperty = getMetaPropertyFromExportsNode(exportsNode);
|
117
107
|
|
118
108
|
if (!metaProperty) {
|
@@ -142,11 +132,6 @@ function checkMetaValidity(context, exportsNode, ruleIsFixable) {
|
|
142
132
|
|
143
133
|
if (!hasMetaSchema(metaProperty)) {
|
144
134
|
context.report(metaProperty, "Rule is missing a meta.schema property.");
|
145
|
-
return;
|
146
|
-
}
|
147
|
-
|
148
|
-
if (ruleIsFixable && !hasMetaFixable(metaProperty)) {
|
149
|
-
context.report(metaProperty, "Rule is fixable, but is missing a meta.fixable property.");
|
150
135
|
}
|
151
136
|
}
|
152
137
|
|
@@ -177,7 +162,6 @@ module.exports = {
|
|
177
162
|
|
178
163
|
create(context) {
|
179
164
|
let exportsNode;
|
180
|
-
let ruleIsFixable = false;
|
181
165
|
|
182
166
|
return {
|
183
167
|
AssignmentExpression(node) {
|
@@ -191,35 +175,13 @@ module.exports = {
|
|
191
175
|
}
|
192
176
|
},
|
193
177
|
|
194
|
-
CallExpression(node) {
|
195
|
-
|
196
|
-
// If the rule has a call for `context.report` and a property `fix`
|
197
|
-
// is being passed in, then we consider that the rule is fixable.
|
198
|
-
//
|
199
|
-
// Note that we only look for context.report() calls in the new
|
200
|
-
// style (with single MessageDescriptor argument), because only
|
201
|
-
// calls in the new style can specify a fix.
|
202
|
-
if (node.callee.type === "MemberExpression" &&
|
203
|
-
node.callee.object.type === "Identifier" &&
|
204
|
-
node.callee.object.name === "context" &&
|
205
|
-
node.callee.property.type === "Identifier" &&
|
206
|
-
node.callee.property.name === "report" &&
|
207
|
-
node.arguments.length === 1 &&
|
208
|
-
node.arguments[0].type === "ObjectExpression") {
|
209
|
-
|
210
|
-
if (getPropertyFromObject("fix", node.arguments[0])) {
|
211
|
-
ruleIsFixable = true;
|
212
|
-
}
|
213
|
-
}
|
214
|
-
},
|
215
|
-
|
216
178
|
"Program:exit"() {
|
217
179
|
if (!isCorrectExportsFormat(exportsNode)) {
|
218
180
|
context.report({ node: exportsNode, message: "Rule does not export an Object. Make sure the rule follows the new rule format." });
|
219
181
|
return;
|
220
182
|
}
|
221
183
|
|
222
|
-
checkMetaValidity(context, exportsNode
|
184
|
+
checkMetaValidity(context, exportsNode);
|
223
185
|
}
|
224
186
|
};
|
225
187
|
}
|
@@ -9,6 +9,8 @@
|
|
9
9
|
// Requirements
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
+
const lodash = require("lodash");
|
13
|
+
|
12
14
|
const astUtils = require("../ast-utils");
|
13
15
|
|
14
16
|
//------------------------------------------------------------------------------
|
@@ -147,7 +149,8 @@ module.exports = {
|
|
147
149
|
upper: null,
|
148
150
|
codePath: null,
|
149
151
|
hasReturn: false,
|
150
|
-
shouldCheck: false
|
152
|
+
shouldCheck: false,
|
153
|
+
node: null
|
151
154
|
};
|
152
155
|
|
153
156
|
/**
|
@@ -168,8 +171,11 @@ module.exports = {
|
|
168
171
|
node,
|
169
172
|
loc: getLocation(node, context.getSourceCode()).loc.start,
|
170
173
|
message: funcInfo.hasReturn
|
171
|
-
? "Expected to return a value at the end of
|
172
|
-
: "Expected to return a value in
|
174
|
+
? "Expected to return a value at the end of {{name}}."
|
175
|
+
: "Expected to return a value in {{name}}.",
|
176
|
+
data: {
|
177
|
+
name: astUtils.getFunctionNameWithKind(funcInfo.node)
|
178
|
+
}
|
173
179
|
});
|
174
180
|
}
|
175
181
|
}
|
@@ -187,7 +193,8 @@ module.exports = {
|
|
187
193
|
node.body.type === "BlockStatement" &&
|
188
194
|
isCallbackOfArrayMethod(node) &&
|
189
195
|
!node.async &&
|
190
|
-
!node.generator
|
196
|
+
!node.generator,
|
197
|
+
node
|
191
198
|
};
|
192
199
|
},
|
193
200
|
|
@@ -204,7 +211,10 @@ module.exports = {
|
|
204
211
|
if (!node.argument) {
|
205
212
|
context.report({
|
206
213
|
node,
|
207
|
-
message: "
|
214
|
+
message: "{{name}} expected a return value.",
|
215
|
+
data: {
|
216
|
+
name: lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node))
|
217
|
+
}
|
208
218
|
});
|
209
219
|
}
|
210
220
|
}
|
@@ -9,6 +9,7 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const LETTER_PATTERN = require("../util/patterns/letters");
|
12
|
+
const astUtils = require("../ast-utils");
|
12
13
|
|
13
14
|
//------------------------------------------------------------------------------
|
14
15
|
// Helpers
|
@@ -16,7 +17,7 @@ const LETTER_PATTERN = require("../util/patterns/letters");
|
|
16
17
|
|
17
18
|
const ALWAYS_MESSAGE = "Comments should not begin with a lowercase character",
|
18
19
|
NEVER_MESSAGE = "Comments should not begin with an uppercase character",
|
19
|
-
DEFAULT_IGNORE_PATTERN =
|
20
|
+
DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
|
20
21
|
WHITESPACE = /\s/g,
|
21
22
|
MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/, // TODO: Combine w/ max-len pattern?
|
22
23
|
DEFAULTS = {
|