eslint 1.7.3 → 1.8.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/README.md +1 -0
- package/conf/eslint.json +2 -0
- package/lib/cli-engine.js +80 -13
- package/lib/cli.js +12 -10
- package/lib/eslint.js +14 -14
- package/lib/logging.js +25 -0
- package/lib/options.js +7 -2
- package/lib/rules/array-bracket-spacing.js +2 -2
- package/lib/rules/arrow-body-style.js +71 -0
- package/lib/rules/comma-spacing.js +72 -36
- package/lib/rules/eol-last.js +10 -4
- package/lib/rules/no-arrow-condition.js +88 -0
- package/lib/rules/no-multiple-empty-lines.js +39 -13
- package/lib/rules/no-plusplus.js +22 -1
- package/lib/rules/no-shadow.js +21 -3
- package/lib/rules/space-in-parens.js +145 -200
- package/lib/rules/valid-jsdoc.js +35 -18
- package/lib/testers/rule-tester.js +62 -7
- package/lib/util/source-code.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
@@ -69,6 +69,7 @@ These folks keep the project moving and are resources for help:
|
|
69
69
|
* Ian VanSchooten ([@ianvs](https://github.com/ianvs)) - committer
|
70
70
|
* Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) - committer
|
71
71
|
* Burak Yiğit Kaya ([@byk](https://github.com/byk)) - committer
|
72
|
+
* Alberto Rodríguez ([@alberto](https://github.com/alberto)) - committer
|
72
73
|
|
73
74
|
## Releases
|
74
75
|
|
package/conf/eslint.json
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
"rules": {
|
5
5
|
"no-alert": 0,
|
6
6
|
"no-array-constructor": 0,
|
7
|
+
"no-arrow-condition": 0,
|
7
8
|
"no-bitwise": 0,
|
8
9
|
"no-caller": 0,
|
9
10
|
"no-catch-shadow": 0,
|
@@ -110,6 +111,7 @@
|
|
110
111
|
"no-magic-numbers": 0,
|
111
112
|
|
112
113
|
"array-bracket-spacing": [0, "never"],
|
114
|
+
"arrow-body-style": [0, "as-needed"],
|
113
115
|
"arrow-parens": 0,
|
114
116
|
"arrow-spacing": 0,
|
115
117
|
"accessor-pairs": 0,
|
package/lib/cli-engine.js
CHANGED
@@ -90,6 +90,10 @@ var defaultOptions = {
|
|
90
90
|
ignorePath: null,
|
91
91
|
parser: DEFAULT_PARSER,
|
92
92
|
cache: false,
|
93
|
+
// in order to honor the cacheFile option if specified
|
94
|
+
// this option should not have a default value otherwise
|
95
|
+
// it will always be used
|
96
|
+
cacheLocation: "",
|
93
97
|
cacheFile: ".eslintcache",
|
94
98
|
fix: false
|
95
99
|
},
|
@@ -338,6 +342,78 @@ function processPath(extensions) {
|
|
338
342
|
};
|
339
343
|
}
|
340
344
|
|
345
|
+
/**
|
346
|
+
* create a md5Hash of a given string
|
347
|
+
* @param {string} str the string to calculate the hash for
|
348
|
+
* @returns {string} the calculated hash
|
349
|
+
*/
|
350
|
+
function md5Hash(str) {
|
351
|
+
return crypto
|
352
|
+
.createHash("md5")
|
353
|
+
.update(str, "utf8")
|
354
|
+
.digest("hex");
|
355
|
+
}
|
356
|
+
|
357
|
+
/**
|
358
|
+
* return the cacheFile to be used by eslint, based on whether the provided parameter is
|
359
|
+
* a directory or looks like a directory (ends in `path.sep`), in which case the file
|
360
|
+
* name will be the `cacheFile/.cache_hashOfCWD`
|
361
|
+
*
|
362
|
+
* if cacheFile points to a file or looks like a file then in will just use that file
|
363
|
+
*
|
364
|
+
* @param {string} cacheFile The name of file to be used to store the cache
|
365
|
+
* @returns {string} the resolved path to the cache file
|
366
|
+
*/
|
367
|
+
function getCacheFile(cacheFile) {
|
368
|
+
// make sure the path separators are normalized for the environment/os
|
369
|
+
// keeping the trailing path separator if present
|
370
|
+
cacheFile = path.normalize(cacheFile);
|
371
|
+
|
372
|
+
var resolvedCacheFile = path.resolve(cacheFile);
|
373
|
+
var looksLikeADirectory = cacheFile[cacheFile.length - 1 ] === path.sep;
|
374
|
+
|
375
|
+
/**
|
376
|
+
* return the name for the cache file in case the provided parameter is a directory
|
377
|
+
* @returns {string} the resolved path to the cacheFile
|
378
|
+
*/
|
379
|
+
function getCacheFileForDirectory() {
|
380
|
+
return path.join(resolvedCacheFile, ".cache_" + md5Hash(process.cwd()));
|
381
|
+
}
|
382
|
+
|
383
|
+
var fileStats;
|
384
|
+
|
385
|
+
try {
|
386
|
+
fileStats = fs.lstatSync(resolvedCacheFile);
|
387
|
+
} catch (ex) {
|
388
|
+
fileStats = null;
|
389
|
+
}
|
390
|
+
|
391
|
+
|
392
|
+
// in case the file exists we need to verify if the provided path
|
393
|
+
// is a directory or a file. If it is a directory we want to create a file
|
394
|
+
// inside that directory
|
395
|
+
if (fileStats) {
|
396
|
+
// is a directory or is a file, but the original file the user provided
|
397
|
+
// looks like a directory but `path.resolve` removed the `last path.sep`
|
398
|
+
// so we need to still treat this like a directory
|
399
|
+
if (fileStats.isDirectory() || looksLikeADirectory) {
|
400
|
+
return getCacheFileForDirectory();
|
401
|
+
}
|
402
|
+
// is file so just use that file
|
403
|
+
return resolvedCacheFile;
|
404
|
+
}
|
405
|
+
|
406
|
+
// here we known the file or directory doesn't exist,
|
407
|
+
// so we will try to infer if its a directory if it looks like a directory
|
408
|
+
// for the current operating system.
|
409
|
+
|
410
|
+
// if the last character passed is a path separator we assume is a directory
|
411
|
+
if (looksLikeADirectory) {
|
412
|
+
return getCacheFileForDirectory();
|
413
|
+
}
|
414
|
+
|
415
|
+
return resolvedCacheFile;
|
416
|
+
}
|
341
417
|
|
342
418
|
//------------------------------------------------------------------------------
|
343
419
|
// Public Interface
|
@@ -356,12 +432,15 @@ function CLIEngine(options) {
|
|
356
432
|
*/
|
357
433
|
this.options = assign(Object.create(defaultOptions), options || {});
|
358
434
|
|
435
|
+
|
436
|
+
var cacheFile = getCacheFile(this.options.cacheLocation || this.options.cacheFile);
|
437
|
+
|
359
438
|
/**
|
360
439
|
* cache used to not operate on files that haven't changed since last successful
|
361
440
|
* execution (e.g. file passed with no errors and no warnings
|
362
441
|
* @type {Object}
|
363
442
|
*/
|
364
|
-
this._fileCache = fileEntryCache.create(
|
443
|
+
this._fileCache = fileEntryCache.create(cacheFile); // eslint-disable-line no-underscore-dangle
|
365
444
|
|
366
445
|
if (!this.options.cache) {
|
367
446
|
this._fileCache.destroy(); // eslint-disable-line no-underscore-dangle
|
@@ -511,18 +590,6 @@ CLIEngine.prototype = {
|
|
511
590
|
ignore: ignoredPathsList
|
512
591
|
};
|
513
592
|
|
514
|
-
/**
|
515
|
-
* create a md5Hash of a given string
|
516
|
-
* @param {string} str the string to calculate the hash for
|
517
|
-
* @returns {string} the calculated hash
|
518
|
-
*/
|
519
|
-
function md5Hash(str) {
|
520
|
-
return crypto
|
521
|
-
.createHash("md5")
|
522
|
-
.update(str)
|
523
|
-
.digest("hex");
|
524
|
-
}
|
525
|
-
|
526
593
|
/**
|
527
594
|
* Calculates the hash of the config file used to validate a given file
|
528
595
|
* @param {string} filename The path of the file to retrieve a config object for to calculate the hash
|
package/lib/cli.js
CHANGED
@@ -22,7 +22,8 @@ var fs = require("fs"),
|
|
22
22
|
|
23
23
|
options = require("./options"),
|
24
24
|
CLIEngine = require("./cli-engine"),
|
25
|
-
mkdirp = require("mkdirp")
|
25
|
+
mkdirp = require("mkdirp"),
|
26
|
+
log = require("./logging");
|
26
27
|
|
27
28
|
//------------------------------------------------------------------------------
|
28
29
|
// Helpers
|
@@ -52,6 +53,7 @@ function translateOptions(cliOptions) {
|
|
52
53
|
parser: cliOptions.parser,
|
53
54
|
cache: cliOptions.cache,
|
54
55
|
cacheFile: cliOptions.cacheFile,
|
56
|
+
cacheLocation: cliOptions.cacheLocation,
|
55
57
|
fix: cliOptions.fix
|
56
58
|
};
|
57
59
|
}
|
@@ -72,7 +74,7 @@ function printResults(engine, results, format, outputFile) {
|
|
72
74
|
|
73
75
|
formatter = engine.getFormatter(format);
|
74
76
|
if (!formatter) {
|
75
|
-
|
77
|
+
log.error("Could not find formatter '%s'.", format);
|
76
78
|
return false;
|
77
79
|
}
|
78
80
|
|
@@ -83,7 +85,7 @@ function printResults(engine, results, format, outputFile) {
|
|
83
85
|
filePath = path.resolve(process.cwd(), outputFile);
|
84
86
|
|
85
87
|
if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
|
86
|
-
|
88
|
+
log.error("Cannot write to output file path, it is a directory: %s", outputFile);
|
87
89
|
return false;
|
88
90
|
}
|
89
91
|
|
@@ -91,11 +93,11 @@ function printResults(engine, results, format, outputFile) {
|
|
91
93
|
mkdirp.sync(path.dirname(filePath));
|
92
94
|
fs.writeFileSync(filePath, output);
|
93
95
|
} catch (ex) {
|
94
|
-
|
96
|
+
log.error("There was a problem writing the output file:\n%s", ex);
|
95
97
|
return false;
|
96
98
|
}
|
97
99
|
} else {
|
98
|
-
|
100
|
+
log.info(output);
|
99
101
|
}
|
100
102
|
}
|
101
103
|
|
@@ -130,7 +132,7 @@ var cli = {
|
|
130
132
|
try {
|
131
133
|
currentOptions = options.parse(args);
|
132
134
|
} catch (error) {
|
133
|
-
|
135
|
+
log.error(error.message);
|
134
136
|
return 1;
|
135
137
|
}
|
136
138
|
|
@@ -138,11 +140,11 @@ var cli = {
|
|
138
140
|
|
139
141
|
if (currentOptions.version) { // version from package.json
|
140
142
|
|
141
|
-
|
143
|
+
log.info("v" + require("../package.json").version);
|
142
144
|
|
143
145
|
} else if (currentOptions.help || (!files.length && !text)) {
|
144
146
|
|
145
|
-
|
147
|
+
log.info(options.generateHelp());
|
146
148
|
|
147
149
|
} else {
|
148
150
|
|
@@ -150,7 +152,7 @@ var cli = {
|
|
150
152
|
|
151
153
|
// disable --fix for piped-in code until we know how to do it correctly
|
152
154
|
if (text && currentOptions.fix) {
|
153
|
-
|
155
|
+
log.error("The --fix option is not available for piped-in code.");
|
154
156
|
return 1;
|
155
157
|
}
|
156
158
|
|
@@ -171,7 +173,7 @@ var cli = {
|
|
171
173
|
tooManyWarnings = currentOptions.maxWarnings >= 0 && report.warningCount > currentOptions.maxWarnings;
|
172
174
|
|
173
175
|
if (!report.errorCount && tooManyWarnings) {
|
174
|
-
|
176
|
+
log.error("ESLint found too many warnings (maximum: %s).", currentOptions.maxWarnings);
|
175
177
|
}
|
176
178
|
|
177
179
|
return (report.errorCount || tooManyWarnings) ? 1 : 0;
|
package/lib/eslint.js
CHANGED
@@ -637,6 +637,20 @@ module.exports = (function() {
|
|
637
637
|
this.reset();
|
638
638
|
}
|
639
639
|
|
640
|
+
// search and apply "eslint-env *".
|
641
|
+
var envInFile = findEslintEnv(text || textOrSourceCode.text);
|
642
|
+
if (envInFile) {
|
643
|
+
if (!config || !config.env) {
|
644
|
+
config = assign({}, config || {}, {env: envInFile});
|
645
|
+
} else {
|
646
|
+
config = assign({}, config);
|
647
|
+
config.env = assign({}, config.env, envInFile);
|
648
|
+
}
|
649
|
+
}
|
650
|
+
|
651
|
+
// process initial config to make it safe to extend
|
652
|
+
config = prepareConfig(config || {});
|
653
|
+
|
640
654
|
// only do this for text
|
641
655
|
if (text !== null) {
|
642
656
|
|
@@ -646,20 +660,6 @@ module.exports = (function() {
|
|
646
660
|
return messages;
|
647
661
|
}
|
648
662
|
|
649
|
-
// search and apply "eslint-env *".
|
650
|
-
var envInFile = findEslintEnv(text);
|
651
|
-
if (envInFile) {
|
652
|
-
if (!config || !config.env) {
|
653
|
-
config = assign({}, config || {}, {env: envInFile});
|
654
|
-
} else {
|
655
|
-
config = assign({}, config);
|
656
|
-
config.env = assign({}, config.env, envInFile);
|
657
|
-
}
|
658
|
-
}
|
659
|
-
|
660
|
-
// process initial config to make it safe to extend
|
661
|
-
config = prepareConfig(config || {});
|
662
|
-
|
663
663
|
ast = parse(text.replace(/^#!([^\r\n]+)/, function(match, captured) {
|
664
664
|
shebang = captured;
|
665
665
|
return "//" + captured;
|
package/lib/logging.js
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Handle logging for Eslint
|
3
|
+
* @author Gyandeep Singh
|
4
|
+
* @copyright 2015 Gyandeep Singh. All rights reserved.
|
5
|
+
*/
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
/* istanbul ignore next */
|
9
|
+
module.exports = {
|
10
|
+
/**
|
11
|
+
* Cover for console.log
|
12
|
+
* @returns {void}
|
13
|
+
*/
|
14
|
+
info: function() {
|
15
|
+
console.log.apply(console, Array.prototype.slice.call(arguments));
|
16
|
+
},
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Cover for console.error
|
20
|
+
* @returns {void}
|
21
|
+
*/
|
22
|
+
error: function() {
|
23
|
+
console.error.apply(console, Array.prototype.slice.call(arguments));
|
24
|
+
}
|
25
|
+
};
|
package/lib/options.js
CHANGED
@@ -69,9 +69,14 @@ module.exports = optionator({
|
|
69
69
|
},
|
70
70
|
{
|
71
71
|
option: "cache-file",
|
72
|
-
type: "String",
|
72
|
+
type: "path::String",
|
73
73
|
default: ".eslintcache",
|
74
|
-
description: "Path to the cache file"
|
74
|
+
description: "Path to the cache file. Deprecated: use --cache-location"
|
75
|
+
},
|
76
|
+
{
|
77
|
+
option: "cache-location",
|
78
|
+
type: "path::String",
|
79
|
+
description: "Path to the cache file or directory"
|
75
80
|
},
|
76
81
|
{
|
77
82
|
heading: "Specifying rules and plugins"
|
@@ -116,7 +116,7 @@ module.exports = function(context) {
|
|
116
116
|
* @returns {boolean} Whether or not the node is an object type.
|
117
117
|
*/
|
118
118
|
function isObjectType(node) {
|
119
|
-
return node.type === "ObjectExpression" || node.type === "ObjectPattern";
|
119
|
+
return node && (node.type === "ObjectExpression" || node.type === "ObjectPattern");
|
120
120
|
}
|
121
121
|
|
122
122
|
/**
|
@@ -125,7 +125,7 @@ module.exports = function(context) {
|
|
125
125
|
* @returns {boolean} Whether or not the node is an array type.
|
126
126
|
*/
|
127
127
|
function isArrayType(node) {
|
128
|
-
return node.type === "ArrayExpression" || node.type === "ArrayPattern";
|
128
|
+
return node && (node.type === "ArrayExpression" || node.type === "ArrayPattern");
|
129
129
|
}
|
130
130
|
|
131
131
|
/**
|
@@ -0,0 +1,71 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Rule to require braces in arrow function body.
|
3
|
+
* @author Alberto Rodríguez
|
4
|
+
* @copyright 2015 Alberto Rodríguez. All rights reserved.
|
5
|
+
* See LICENSE file in root directory for full license.
|
6
|
+
*/
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
// Rule Definition
|
11
|
+
//------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
module.exports = function(context) {
|
14
|
+
var always = context.options[0] === "always";
|
15
|
+
var asNeeded = !context.options[0] || context.options[0] === "as-needed";
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Determines whether a arrow function body needs braces
|
19
|
+
* @param {ASTNode} node The arrow function node.
|
20
|
+
* @returns {void}
|
21
|
+
*/
|
22
|
+
function validate(node) {
|
23
|
+
var arrowBody = node.body;
|
24
|
+
if (arrowBody.type === "BlockStatement") {
|
25
|
+
var blockBody = arrowBody.body;
|
26
|
+
|
27
|
+
if (blockBody.length > 1) {
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
|
31
|
+
if (blockBody.length === 0) {
|
32
|
+
var hasComments = context.getComments(arrowBody).trailing.length > 0;
|
33
|
+
if (hasComments) {
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
|
37
|
+
context.report({
|
38
|
+
node: node,
|
39
|
+
loc: arrowBody.loc.start,
|
40
|
+
message: "Unexpected empty block in arrow body."
|
41
|
+
});
|
42
|
+
} else {
|
43
|
+
if (asNeeded && blockBody[0].type === "ReturnStatement") {
|
44
|
+
context.report({
|
45
|
+
node: node,
|
46
|
+
loc: arrowBody.loc.start,
|
47
|
+
message: "Unexpected block statement surrounding arrow body."
|
48
|
+
});
|
49
|
+
}
|
50
|
+
}
|
51
|
+
} else {
|
52
|
+
if (always) {
|
53
|
+
context.report({
|
54
|
+
node: node,
|
55
|
+
loc: arrowBody.loc.start,
|
56
|
+
message: "Expected block statement surrounding arrow body."
|
57
|
+
});
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
return {
|
63
|
+
"ArrowFunctionExpression": validate
|
64
|
+
};
|
65
|
+
};
|
66
|
+
|
67
|
+
module.exports.schema = [
|
68
|
+
{
|
69
|
+
"enum": ["always", "as-needed"]
|
70
|
+
}
|
71
|
+
];
|
@@ -41,42 +41,6 @@ module.exports = function(context) {
|
|
41
41
|
return !!token && (token.type === "Punctuator") && (token.value === ",");
|
42
42
|
}
|
43
43
|
|
44
|
-
/**
|
45
|
-
* Reports a spacing error with an appropriate message.
|
46
|
-
* @param {ASTNode} node The binary expression node to report.
|
47
|
-
* @param {string} dir Is the error "before" or "after" the comma?
|
48
|
-
* @returns {void}
|
49
|
-
* @private
|
50
|
-
*/
|
51
|
-
function report(node, dir) {
|
52
|
-
context.report(node, options[dir] ?
|
53
|
-
"A space is required " + dir + " ','." :
|
54
|
-
"There should be no space " + dir + " ','.");
|
55
|
-
}
|
56
|
-
|
57
|
-
/**
|
58
|
-
* Validates the spacing around a comma token.
|
59
|
-
* @param {Object} tokens - The tokens to be validated.
|
60
|
-
* @param {Token} tokens.comma The token representing the comma.
|
61
|
-
* @param {Token} [tokens.left] The last token before the comma.
|
62
|
-
* @param {Token} [tokens.right] The first token after the comma.
|
63
|
-
* @param {Token|ASTNode} reportItem The item to use when reporting an error.
|
64
|
-
* @returns {void}
|
65
|
-
* @private
|
66
|
-
*/
|
67
|
-
function validateCommaItemSpacing(tokens, reportItem) {
|
68
|
-
if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) &&
|
69
|
-
(options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma))
|
70
|
-
) {
|
71
|
-
report(reportItem, "before");
|
72
|
-
}
|
73
|
-
if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) &&
|
74
|
-
(options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right))
|
75
|
-
) {
|
76
|
-
report(reportItem, "after");
|
77
|
-
}
|
78
|
-
}
|
79
|
-
|
80
44
|
/**
|
81
45
|
* Determines if a given source index is in a comment or not by checking
|
82
46
|
* the index against the comment range. Since the check goes straight
|
@@ -90,6 +54,7 @@ module.exports = function(context) {
|
|
90
54
|
function isIndexInComment(index, comments) {
|
91
55
|
|
92
56
|
var comment;
|
57
|
+
lastCommentIndex = 0;
|
93
58
|
|
94
59
|
while (lastCommentIndex < comments.length) {
|
95
60
|
|
@@ -108,6 +73,77 @@ module.exports = function(context) {
|
|
108
73
|
return false;
|
109
74
|
}
|
110
75
|
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Reports a spacing error with an appropriate message.
|
79
|
+
* @param {ASTNode} node The binary expression node to report.
|
80
|
+
* @param {string} dir Is the error "before" or "after" the comma?
|
81
|
+
* @param {ASTNode} otherNode The node at the left or right of `node`
|
82
|
+
* @returns {void}
|
83
|
+
* @private
|
84
|
+
*/
|
85
|
+
function report(node, dir, otherNode) {
|
86
|
+
context.report({
|
87
|
+
node: node,
|
88
|
+
fix: function(fixer) {
|
89
|
+
if (options[dir]) {
|
90
|
+
if (dir === "before") {
|
91
|
+
return fixer.insertTextBefore(node, " ");
|
92
|
+
} else {
|
93
|
+
return fixer.insertTextAfter(node, " ");
|
94
|
+
}
|
95
|
+
} else {
|
96
|
+
/*
|
97
|
+
* Comments handling
|
98
|
+
*/
|
99
|
+
var start, end;
|
100
|
+
var newText = "";
|
101
|
+
|
102
|
+
if (dir === "before") {
|
103
|
+
start = otherNode.range[1];
|
104
|
+
end = node.range[0];
|
105
|
+
} else {
|
106
|
+
start = node.range[1];
|
107
|
+
end = otherNode.range[0];
|
108
|
+
}
|
109
|
+
|
110
|
+
for (var i = start; i < end; i++) {
|
111
|
+
if (isIndexInComment(i, allComments)) {
|
112
|
+
newText += context.getSource()[i];
|
113
|
+
}
|
114
|
+
}
|
115
|
+
return fixer.replaceTextRange([start, end], newText);
|
116
|
+
}
|
117
|
+
},
|
118
|
+
message: options[dir] ?
|
119
|
+
"A space is required " + dir + " ','." :
|
120
|
+
"There should be no space " + dir + " ','."
|
121
|
+
});
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Validates the spacing around a comma token.
|
126
|
+
* @param {Object} tokens - The tokens to be validated.
|
127
|
+
* @param {Token} tokens.comma The token representing the comma.
|
128
|
+
* @param {Token} [tokens.left] The last token before the comma.
|
129
|
+
* @param {Token} [tokens.right] The first token after the comma.
|
130
|
+
* @param {Token|ASTNode} reportItem The item to use when reporting an error.
|
131
|
+
* @returns {void}
|
132
|
+
* @private
|
133
|
+
*/
|
134
|
+
function validateCommaItemSpacing(tokens, reportItem) {
|
135
|
+
if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) &&
|
136
|
+
(options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma))
|
137
|
+
) {
|
138
|
+
report(reportItem, "before", tokens.left);
|
139
|
+
}
|
140
|
+
if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) &&
|
141
|
+
(options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right))
|
142
|
+
) {
|
143
|
+
report(reportItem, "after", tokens.right);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
111
147
|
/**
|
112
148
|
* Adds null elements of the given ArrayExpression or ArrayPattern node to the ignore list.
|
113
149
|
* @param {ASTNode} node An ArrayExpression or ArrayPattern node.
|
package/lib/rules/eol-last.js
CHANGED
@@ -18,8 +18,10 @@ module.exports = function(context) {
|
|
18
18
|
|
19
19
|
"Program": function checkBadEOF(node) {
|
20
20
|
// Get the whole source code, not for node only.
|
21
|
-
var src = context.getSource(),
|
22
|
-
|
21
|
+
var src = context.getSource(),
|
22
|
+
location = {column: 1},
|
23
|
+
linebreakStyle = context.options[0] || "unix",
|
24
|
+
linebreak = linebreakStyle === "unix" ? "\n" : "\r\n";
|
23
25
|
if (src.length === 0) {
|
24
26
|
return;
|
25
27
|
}
|
@@ -32,7 +34,7 @@ module.exports = function(context) {
|
|
32
34
|
loc: location,
|
33
35
|
message: "Newline required at end of file but not found.",
|
34
36
|
fix: function(fixer) {
|
35
|
-
return fixer.insertTextAfterRange([0, src.length],
|
37
|
+
return fixer.insertTextAfterRange([0, src.length], linebreak);
|
36
38
|
}
|
37
39
|
});
|
38
40
|
}
|
@@ -42,4 +44,8 @@ module.exports = function(context) {
|
|
42
44
|
|
43
45
|
};
|
44
46
|
|
45
|
-
module.exports.schema = [
|
47
|
+
module.exports.schema = [
|
48
|
+
{
|
49
|
+
"enum": ["unix", "windows"]
|
50
|
+
}
|
51
|
+
];
|
@@ -0,0 +1,88 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview A rule to warn against using arrow functions in conditions.
|
3
|
+
* @author Jxck <https://github.com/Jxck>
|
4
|
+
* @copyright 2015 Luke Karrys. All rights reserved.
|
5
|
+
* The MIT License (MIT)
|
6
|
+
|
7
|
+
* Copyright (c) 2015 Jxck
|
8
|
+
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
* of this software and associated documentation files (the "Software"), to deal
|
11
|
+
* in the Software without restriction, including without limitation the rights
|
12
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
* copies of the Software, and to permit persons to whom the Software is
|
14
|
+
* furnished to do so, subject to the following conditions:
|
15
|
+
|
16
|
+
* The above copyright notice and this permission notice shall be included in all
|
17
|
+
* copies or substantial portions of the Software.
|
18
|
+
|
19
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
25
|
+
* SOFTWARE.
|
26
|
+
*/
|
27
|
+
|
28
|
+
"use strict";
|
29
|
+
|
30
|
+
//------------------------------------------------------------------------------
|
31
|
+
// Helpers
|
32
|
+
//------------------------------------------------------------------------------
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Checks whether or not a node is an arrow function expression.
|
36
|
+
* @param {ASTNode} node - node to test
|
37
|
+
* @returns {boolean} `true` if the node is an arrow function expression.
|
38
|
+
*/
|
39
|
+
function isArrowFunction(node) {
|
40
|
+
return node.test && node.test.type === "ArrowFunctionExpression";
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Checks whether or not a node is a conditional expression.
|
45
|
+
* @param {ASTNode} node - node to test
|
46
|
+
* @returns {boolean} `true` if the node is a conditional expression.
|
47
|
+
*/
|
48
|
+
function isConditional(node) {
|
49
|
+
return node.body && node.body.type === "ConditionalExpression";
|
50
|
+
}
|
51
|
+
|
52
|
+
//------------------------------------------------------------------------------
|
53
|
+
// Rule Definition
|
54
|
+
//------------------------------------------------------------------------------
|
55
|
+
|
56
|
+
module.exports = function(context) {
|
57
|
+
/**
|
58
|
+
* Reports if a conditional statement is an arrow function.
|
59
|
+
* @param {ASTNode} node - A node to check and report.
|
60
|
+
* @returns {void}
|
61
|
+
*/
|
62
|
+
function checkCondition(node) {
|
63
|
+
if (isArrowFunction(node)) {
|
64
|
+
context.report(node, "Arrow function `=>` used inside {{statementType}} instead of comparison operator.", {statementType: node.type});
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Reports if an arrow function contains an ambiguous conditional.
|
70
|
+
* @param {ASTNode} node - A node to check and report.
|
71
|
+
* @returns {void}
|
72
|
+
*/
|
73
|
+
function checkArrowFunc(node) {
|
74
|
+
if (isConditional(node)) {
|
75
|
+
context.report(node, "Arrow function used ambiguously with a conditional expression.");
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
return {
|
80
|
+
"IfStatement": checkCondition,
|
81
|
+
"WhileStatement": checkCondition,
|
82
|
+
"ForStatement": checkCondition,
|
83
|
+
"ConditionalExpression": checkCondition,
|
84
|
+
"ArrowFunctionExpression": checkArrowFunc
|
85
|
+
};
|
86
|
+
};
|
87
|
+
|
88
|
+
module.exports.schema = [];
|