eslint 1.4.1 → 1.5.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/README.md +1 -1
- package/bin/eslint.js +32 -3
- package/lib/ast-utils.js +17 -11
- package/lib/cli-engine.js +72 -11
- package/lib/config.js +54 -55
- package/lib/eslint.js +7 -56
- package/lib/options.js +7 -0
- package/lib/rules/array-bracket-spacing.js +6 -5
- package/lib/rules/block-spacing.js +4 -3
- package/lib/rules/comma-dangle.js +25 -10
- package/lib/rules/comma-spacing.js +4 -29
- package/lib/rules/computed-property-spacing.js +5 -4
- package/lib/rules/eol-last.js +8 -1
- package/lib/rules/func-style.js +29 -9
- package/lib/rules/id-length.js +3 -3
- package/lib/rules/indent.js +100 -47
- package/lib/rules/jsx-quotes.js +1 -1
- package/lib/rules/key-spacing.js +7 -1
- package/lib/rules/no-dupe-args.js +30 -46
- package/lib/rules/no-extra-semi.js +7 -1
- package/lib/rules/no-inline-comments.js +3 -1
- package/lib/rules/no-spaced-func.js +18 -5
- package/lib/rules/no-trailing-spaces.js +34 -6
- package/lib/rules/no-unused-vars.js +4 -4
- package/lib/rules/no-warning-comments.js +7 -0
- package/lib/rules/object-curly-spacing.js +7 -9
- package/lib/rules/semi-spacing.js +29 -4
- package/lib/rules/space-after-keywords.js +27 -5
- package/lib/rules/space-before-blocks.js +64 -7
- package/lib/rules/space-before-function-paren.js +19 -13
- package/lib/rules/space-before-keywords.js +45 -17
- package/lib/rules/space-infix-ops.js +22 -1
- package/lib/rules/space-return-throw-case.js +7 -1
- package/lib/testers/event-generator-tester.js +63 -0
- package/lib/util/comment-event-generator.js +116 -0
- package/lib/util/node-event-generator.js +55 -0
- package/lib/util/source-code.js +14 -7
- package/package.json +2 -2
package/README.md
CHANGED
@@ -104,7 +104,7 @@ The following projects are using ESLint to validate their JavaScript:
|
|
104
104
|
|
105
105
|
* [Drupal](https://www.drupal.org/node/2274223)
|
106
106
|
* [Esprima](https://github.com/ariya/esprima)
|
107
|
-
* [
|
107
|
+
* [Node.js](https://github.com/nodejs/node/commit/f9dd34d301ab385ae316769b85ef916f9b70b6f6)
|
108
108
|
* [WebKit](https://bugs.webkit.org/show_bug.cgi?id=125048)
|
109
109
|
|
110
110
|
In addition, the following companies are using ESLint internally to validate their JavaScript:
|
package/bin/eslint.js
CHANGED
@@ -1,11 +1,40 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @fileoverview Main CLI that is run via the eslint command.
|
5
|
+
* @author Nicholas C. Zakas
|
6
|
+
* @copyright 2013 Nicholas C. Zakas. All rights reserved.
|
7
|
+
* See LICENSE file in root directory for full license.
|
8
|
+
*/
|
9
|
+
|
10
|
+
"use strict";
|
11
|
+
|
12
|
+
//------------------------------------------------------------------------------
|
13
|
+
// Helpers
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
|
16
|
+
var exitCode = 0,
|
17
|
+
useStdIn = (process.argv.indexOf("--stdin") > -1),
|
18
|
+
init = (process.argv.indexOf("--init") > -1),
|
19
|
+
debug = (process.argv.indexOf("--debug") > -1);
|
20
|
+
|
21
|
+
// must do this initialization *before* other requires in order to work
|
22
|
+
if (debug) {
|
23
|
+
require("debug").enable("eslint:*");
|
24
|
+
}
|
25
|
+
|
26
|
+
//------------------------------------------------------------------------------
|
27
|
+
// Requirements
|
28
|
+
//------------------------------------------------------------------------------
|
29
|
+
|
30
|
+
// now we can safely include the other modules that use debug
|
2
31
|
var concat = require("concat-stream"),
|
3
32
|
configInit = require("../lib/config-initializer"),
|
4
33
|
cli = require("../lib/cli");
|
5
34
|
|
6
|
-
|
7
|
-
|
8
|
-
|
35
|
+
//------------------------------------------------------------------------------
|
36
|
+
// Execution
|
37
|
+
//------------------------------------------------------------------------------
|
9
38
|
|
10
39
|
if (useStdIn) {
|
11
40
|
process.stdin.pipe(concat({ encoding: "string" }, function(text) {
|
package/lib/ast-utils.js
CHANGED
@@ -37,17 +37,6 @@ function isModifyingReference(reference, index, references) {
|
|
37
37
|
|
38
38
|
module.exports = {
|
39
39
|
|
40
|
-
/**
|
41
|
-
* Determines whether two adjacent tokens are have whitespace between them.
|
42
|
-
* @param {Object} left - The left token object.
|
43
|
-
* @param {Object} right - The right token object.
|
44
|
-
* @returns {boolean} Whether or not there is space between the tokens.
|
45
|
-
* @public
|
46
|
-
*/
|
47
|
-
isTokenSpaced: function(left, right) {
|
48
|
-
return left.range[1] < right.range[0];
|
49
|
-
},
|
50
|
-
|
51
40
|
/**
|
52
41
|
* Determines whether two adjacent tokens are on the same line.
|
53
42
|
* @param {Object} left - The left token object.
|
@@ -104,5 +93,22 @@ module.exports = {
|
|
104
93
|
*/
|
105
94
|
isSurroundedBy: function(val, character) {
|
106
95
|
return val[0] === character && val[val.length - 1] === character;
|
96
|
+
},
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Returns whether the provided node is an ESLint directive comment or not
|
100
|
+
* @param {LineComment|BlockComment} node The node to be checked
|
101
|
+
* @returns {boolean} `true` if the node is an ESLint directive comment
|
102
|
+
*/
|
103
|
+
isDirectiveComment: function(node) {
|
104
|
+
var comment = node.value.trim();
|
105
|
+
return (
|
106
|
+
node.type === "Line" && comment.indexOf("eslint-") === 0 ||
|
107
|
+
node.type === "Block" && (
|
108
|
+
comment.indexOf("global ") === 0 ||
|
109
|
+
comment.indexOf("eslint ") === 0 ||
|
110
|
+
comment.indexOf("eslint-") === 0
|
111
|
+
)
|
112
|
+
);
|
107
113
|
}
|
108
114
|
};
|
package/lib/cli-engine.js
CHANGED
@@ -32,7 +32,10 @@ var fs = require("fs"),
|
|
32
32
|
util = require("./util"),
|
33
33
|
fileEntryCache = require("file-entry-cache"),
|
34
34
|
SourceCodeFixer = require("./util/source-code-fixer"),
|
35
|
-
validator = require("./config-validator")
|
35
|
+
validator = require("./config-validator"),
|
36
|
+
|
37
|
+
crypto = require( "crypto" ),
|
38
|
+
pkg = require("../package.json");
|
36
39
|
|
37
40
|
var DEFAULT_PARSER = require("../conf/eslint.json").parser;
|
38
41
|
|
@@ -321,12 +324,13 @@ function processPath(extensions) {
|
|
321
324
|
*
|
322
325
|
* @param {string} pathname The directory path to be modified
|
323
326
|
* @returns {string} The glob path or the file path itself
|
327
|
+
* @private
|
324
328
|
*/
|
325
329
|
return function(pathname) {
|
326
330
|
var newPath = pathname;
|
327
331
|
|
328
332
|
if (shell.test("-d", pathname)) {
|
329
|
-
newPath = pathname + suffix;
|
333
|
+
newPath = pathname.replace(/[\/\\]$/, "") + suffix;
|
330
334
|
}
|
331
335
|
|
332
336
|
return newPath.replace(/\\/g, "/").replace(/^\.\//, "");
|
@@ -466,6 +470,20 @@ CLIEngine.prototype = {
|
|
466
470
|
loadedPlugins[pluginNameWithoutPrefix] = pluginobject;
|
467
471
|
},
|
468
472
|
|
473
|
+
/**
|
474
|
+
* Resolves the patterns passed into executeOnFiles() into glob-based patterns
|
475
|
+
* for easier handling.
|
476
|
+
* @param {string[]} patterns The file patterns passed on the command line.
|
477
|
+
* @returns {string[]} The equivalent glob patterns.
|
478
|
+
*/
|
479
|
+
resolveFileGlobPatterns: function(patterns) {
|
480
|
+
var extensions = this.options.extensions.map(function(ext) {
|
481
|
+
return ext.charAt(0) === "." ? ext.substr(1) : ext;
|
482
|
+
});
|
483
|
+
|
484
|
+
return patterns.map(processPath(extensions));
|
485
|
+
},
|
486
|
+
|
469
487
|
/**
|
470
488
|
* Executes the current configuration on an array of file and directory names.
|
471
489
|
* @param {string[]} patterns An array of file and directory names.
|
@@ -479,23 +497,57 @@ CLIEngine.prototype = {
|
|
479
497
|
configHelper = new Config(options),
|
480
498
|
ignoredPaths = IgnoredPaths.load(options),
|
481
499
|
ignoredPathsList = ignoredPaths.patterns || [],
|
482
|
-
extensions = options.extensions.map(function(ext) {
|
483
|
-
return ext.charAt(0) === "." ? ext.substr(1) : ext;
|
484
|
-
}),
|
485
500
|
globOptions,
|
486
501
|
stats,
|
487
|
-
startTime
|
502
|
+
startTime,
|
503
|
+
prevConfig; // the previous configuration used
|
488
504
|
|
489
505
|
startTime = Date.now();
|
490
|
-
|
491
|
-
patterns = patterns.map(processPath(extensions));
|
492
|
-
ignoredPathsList = ignoredPathsList.map(processPath());
|
506
|
+
patterns = this.resolveFileGlobPatterns(patterns);
|
493
507
|
|
494
508
|
globOptions = {
|
495
509
|
nodir: true,
|
496
510
|
ignore: ignoredPathsList
|
497
511
|
};
|
498
512
|
|
513
|
+
/**
|
514
|
+
* create a md5Hash of a given string
|
515
|
+
* @param {string} str the string to calculate the hash for
|
516
|
+
* @returns {string} the calculated hash
|
517
|
+
*/
|
518
|
+
function md5Hash(str) {
|
519
|
+
return crypto
|
520
|
+
.createHash("md5")
|
521
|
+
.update(str)
|
522
|
+
.digest("hex");
|
523
|
+
}
|
524
|
+
|
525
|
+
/**
|
526
|
+
* Calculates the hash of the config file used to validate a given file
|
527
|
+
* @param {string} filename The path of the file to retrieve a config object for to calculate the hash
|
528
|
+
* @returns {string} the hash of the config
|
529
|
+
*/
|
530
|
+
function hashOfConfigFor(filename) {
|
531
|
+
var config = configHelper.getConfig(filename);
|
532
|
+
|
533
|
+
if (!prevConfig) {
|
534
|
+
prevConfig = {};
|
535
|
+
}
|
536
|
+
|
537
|
+
// reuse the previously hashed config if the config hasn't changed
|
538
|
+
if (prevConfig.config !== config) {
|
539
|
+
// config changed so we need to calculate the hash of the config
|
540
|
+
// and the hash of the plugins being used
|
541
|
+
prevConfig.config = config;
|
542
|
+
|
543
|
+
var eslintVersion = pkg.version;
|
544
|
+
|
545
|
+
prevConfig.hash = md5Hash(eslintVersion + "_" + JSON.stringify(config));
|
546
|
+
}
|
547
|
+
|
548
|
+
return prevConfig.hash;
|
549
|
+
}
|
550
|
+
|
499
551
|
/**
|
500
552
|
* Executes the linter on a file defined by the `filename`. Skips
|
501
553
|
* unsupported file extensions and any files that are already linted.
|
@@ -503,18 +555,26 @@ CLIEngine.prototype = {
|
|
503
555
|
* @returns {void}
|
504
556
|
*/
|
505
557
|
function executeOnFile(filename) {
|
558
|
+
var shouldIgnore = ignoredPaths.contains(filename);
|
506
559
|
filename = fs.realpathSync(filename);
|
507
560
|
|
508
|
-
if (processed[filename]) {
|
561
|
+
if (processed[filename] || shouldIgnore) {
|
509
562
|
return;
|
510
563
|
}
|
511
564
|
|
565
|
+
var hashOfConfig;
|
566
|
+
|
512
567
|
if (options.cache) {
|
513
568
|
// get the descriptor for this file
|
514
569
|
// with the metadata and the flag that determines if
|
515
570
|
// the file has changed
|
516
571
|
var descriptor = fileCache.getFileDescriptor(filename);
|
517
|
-
|
572
|
+
var meta = descriptor.meta || {};
|
573
|
+
|
574
|
+
hashOfConfig = hashOfConfigFor(filename);
|
575
|
+
|
576
|
+
var changed = descriptor.changed || meta.hashOfConfig !== hashOfConfig;
|
577
|
+
if (!changed) {
|
518
578
|
debug("Skipping file since hasn't changed: " + filename);
|
519
579
|
|
520
580
|
// Adding the filename to the processed hashmap
|
@@ -551,6 +611,7 @@ CLIEngine.prototype = {
|
|
551
611
|
// since the file passed we store the result here
|
552
612
|
// TODO: check this as we might not need to store the
|
553
613
|
// successful runs as it will always should be 0 error 0 warnings
|
614
|
+
descriptor.meta.hashOfConfig = hashOfConfig;
|
554
615
|
descriptor.meta.results = res;
|
555
616
|
}
|
556
617
|
}
|
package/lib/config.js
CHANGED
@@ -69,6 +69,44 @@ function isObject(item) {
|
|
69
69
|
return typeof item === "object" && !Array.isArray(item) && item !== null;
|
70
70
|
}
|
71
71
|
|
72
|
+
/**
|
73
|
+
* Creates an environment config based on the specified environments.
|
74
|
+
* @param {Object<string,boolean>} envs The environment settings.
|
75
|
+
* @returns {Object} A configuration object with the appropriate rules and globals
|
76
|
+
* set.
|
77
|
+
* @private
|
78
|
+
*/
|
79
|
+
function createEnvironmentConfig(envs) {
|
80
|
+
|
81
|
+
var envConfig = {
|
82
|
+
globals: {},
|
83
|
+
env: envs || {},
|
84
|
+
rules: {},
|
85
|
+
ecmaFeatures: {}
|
86
|
+
};
|
87
|
+
|
88
|
+
if (envs) {
|
89
|
+
Object.keys(envs).filter(function(name) {
|
90
|
+
return envs[name];
|
91
|
+
}).forEach(function(name) {
|
92
|
+
var environment = environments[name];
|
93
|
+
|
94
|
+
if (environment) {
|
95
|
+
|
96
|
+
if (environment.globals) {
|
97
|
+
assign(envConfig.globals, environment.globals);
|
98
|
+
}
|
99
|
+
|
100
|
+
if (environment.ecmaFeatures) {
|
101
|
+
assign(envConfig.ecmaFeatures, environment.ecmaFeatures);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
});
|
105
|
+
}
|
106
|
+
|
107
|
+
return envConfig;
|
108
|
+
}
|
109
|
+
|
72
110
|
/**
|
73
111
|
* Read the config from the config JSON file
|
74
112
|
* @param {string} filePath the path to the JSON config file
|
@@ -175,6 +213,10 @@ function loadConfig(configToLoad) {
|
|
175
213
|
|
176
214
|
}
|
177
215
|
|
216
|
+
if (config.env) {
|
217
|
+
// Merge in environment-specific globals and ecmaFeatures.
|
218
|
+
config = util.mergeConfigs(createEnvironmentConfig(config.env), config);
|
219
|
+
}
|
178
220
|
|
179
221
|
}
|
180
222
|
|
@@ -253,14 +295,16 @@ function getLocalConfig(thisConfig, directory) {
|
|
253
295
|
config = {},
|
254
296
|
localConfigFiles = thisConfig.findLocalConfigFiles(directory),
|
255
297
|
numFiles = localConfigFiles.length,
|
256
|
-
rootPath
|
298
|
+
rootPath,
|
299
|
+
projectConfigPath = path.join(process.cwd(), LOCAL_CONFIG_FILENAME);
|
257
300
|
|
258
301
|
for (i = 0; i < numFiles; i++) {
|
259
302
|
|
260
303
|
localConfigFile = localConfigFiles[i];
|
261
304
|
|
262
|
-
// Don't consider the personal config file in the home directory
|
263
|
-
if
|
305
|
+
// Don't consider the personal config file in the home directory,
|
306
|
+
// except if the home directory is the same as the current working directory
|
307
|
+
if (localConfigFile === PERSONAL_CONFIG_PATH && localConfigFile !== projectConfigPath) {
|
264
308
|
continue;
|
265
309
|
}
|
266
310
|
|
@@ -291,44 +335,6 @@ function getLocalConfig(thisConfig, directory) {
|
|
291
335
|
return found ? config : util.mergeConfigs(config, getPersonalConfig());
|
292
336
|
}
|
293
337
|
|
294
|
-
/**
|
295
|
-
* Creates an environment config based on the specified environments.
|
296
|
-
* @param {Object<string,boolean>} envs The environment settings.
|
297
|
-
* @returns {Object} A configuration object with the appropriate rules and globals
|
298
|
-
* set.
|
299
|
-
* @private
|
300
|
-
*/
|
301
|
-
function createEnvironmentConfig(envs) {
|
302
|
-
|
303
|
-
var envConfig = {
|
304
|
-
globals: {},
|
305
|
-
env: envs || {},
|
306
|
-
rules: {},
|
307
|
-
ecmaFeatures: {}
|
308
|
-
};
|
309
|
-
|
310
|
-
if (envs) {
|
311
|
-
Object.keys(envs).filter(function(name) {
|
312
|
-
return envs[name];
|
313
|
-
}).forEach(function(name) {
|
314
|
-
var environment = environments[name];
|
315
|
-
|
316
|
-
if (environment) {
|
317
|
-
|
318
|
-
if (environment.globals) {
|
319
|
-
assign(envConfig.globals, environment.globals);
|
320
|
-
}
|
321
|
-
|
322
|
-
if (environment.ecmaFeatures) {
|
323
|
-
assign(envConfig.ecmaFeatures, environment.ecmaFeatures);
|
324
|
-
}
|
325
|
-
}
|
326
|
-
});
|
327
|
-
}
|
328
|
-
|
329
|
-
return envConfig;
|
330
|
-
}
|
331
|
-
|
332
338
|
//------------------------------------------------------------------------------
|
333
339
|
// API
|
334
340
|
//------------------------------------------------------------------------------
|
@@ -412,44 +418,37 @@ Config.prototype.getConfig = function(filePath) {
|
|
412
418
|
// Step 2: Create a copy of the baseConfig
|
413
419
|
config = util.mergeConfigs({parser: this.parser}, this.baseConfig);
|
414
420
|
|
415
|
-
// Step 3: Merge in
|
416
|
-
config = util.mergeConfigs(config, createEnvironmentConfig(userConfig.env));
|
417
|
-
|
418
|
-
// Step 4: Merge in the user-specified configuration from .eslintrc and package.json
|
421
|
+
// Step 3: Merge in the user-specified configuration from .eslintrc and package.json
|
419
422
|
config = util.mergeConfigs(config, userConfig);
|
420
423
|
|
421
|
-
// Step
|
424
|
+
// Step 4: Merge in command line config file
|
422
425
|
if (this.useSpecificConfig) {
|
423
426
|
debug("Merging command line config file");
|
424
427
|
|
425
|
-
if (this.useSpecificConfig.env) {
|
426
|
-
config = util.mergeConfigs(config, createEnvironmentConfig(this.useSpecificConfig.env));
|
427
|
-
}
|
428
|
-
|
429
428
|
config = util.mergeConfigs(config, this.useSpecificConfig);
|
430
429
|
}
|
431
430
|
|
432
|
-
// Step
|
431
|
+
// Step 5: Merge in command line environments
|
433
432
|
debug("Merging command line environment settings");
|
434
433
|
config = util.mergeConfigs(config, createEnvironmentConfig(this.env));
|
435
434
|
|
436
|
-
// Step
|
435
|
+
// Step 6: Merge in command line rules
|
437
436
|
if (this.options.rules) {
|
438
437
|
debug("Merging command line rules");
|
439
438
|
config = util.mergeConfigs(config, { rules: this.options.rules });
|
440
439
|
}
|
441
440
|
|
442
|
-
// Step
|
441
|
+
// Step 7: Merge in command line globals
|
443
442
|
config = util.mergeConfigs(config, { globals: this.globals });
|
444
443
|
|
445
|
-
// Step
|
444
|
+
// Step 8: Merge in command line plugins
|
446
445
|
if (this.options.plugins) {
|
447
446
|
debug("Merging command line plugins");
|
448
447
|
pluginConfig = getPluginsConfig(this.options.plugins);
|
449
448
|
config = util.mergeConfigs(config, { plugins: this.options.plugins });
|
450
449
|
}
|
451
450
|
|
452
|
-
// Step
|
451
|
+
// Step 9: Merge in plugin specific rules in reverse
|
453
452
|
if (config.plugins) {
|
454
453
|
pluginConfig = getPluginsConfig(config.plugins);
|
455
454
|
config = util.mergeConfigs(pluginConfig, config);
|
package/lib/eslint.js
CHANGED
@@ -20,6 +20,8 @@ var estraverse = require("estraverse-fb"),
|
|
20
20
|
RuleContext = require("./rule-context"),
|
21
21
|
timing = require("./timing"),
|
22
22
|
SourceCode = require("./util/source-code"),
|
23
|
+
NodeEventGenerator = require("./util/node-event-generator"),
|
24
|
+
CommentEventGenerator = require("./util/comment-event-generator"),
|
23
25
|
EventEmitter = require("events").EventEmitter,
|
24
26
|
validator = require("./config-validator"),
|
25
27
|
replacements = require("../conf/replacements.json");
|
@@ -498,8 +500,6 @@ module.exports = (function() {
|
|
498
500
|
currentFilename = null,
|
499
501
|
controller = null,
|
500
502
|
reportingConfig = [],
|
501
|
-
commentLocsEnter = [],
|
502
|
-
commentLocsExit = [],
|
503
503
|
sourceCode = null;
|
504
504
|
|
505
505
|
/**
|
@@ -564,46 +564,6 @@ module.exports = (function() {
|
|
564
564
|
}
|
565
565
|
}
|
566
566
|
|
567
|
-
/**
|
568
|
-
* Check collection of comments to prevent double event for comment as
|
569
|
-
* leading and trailing, then emit event if passing
|
570
|
-
* @param {ASTNode[]} comments Collection of comment nodes
|
571
|
-
* @param {Object[]} locs List of locations of previous comment nodes
|
572
|
-
* @param {string} eventName Event name postfix
|
573
|
-
* @returns {void}
|
574
|
-
*/
|
575
|
-
function emitComments(comments, locs, eventName) {
|
576
|
-
|
577
|
-
if (comments.length) {
|
578
|
-
comments.forEach(function(node) {
|
579
|
-
if (locs.indexOf(node.loc) >= 0) {
|
580
|
-
locs.splice(locs.indexOf(node.loc), 1);
|
581
|
-
} else {
|
582
|
-
locs.push(node.loc);
|
583
|
-
api.emit(node.type + eventName, node);
|
584
|
-
}
|
585
|
-
});
|
586
|
-
}
|
587
|
-
}
|
588
|
-
|
589
|
-
/**
|
590
|
-
* Shortcut to check and emit enter of comment nodes
|
591
|
-
* @param {ASTNode[]} comments Collection of comment nodes
|
592
|
-
* @returns {void}
|
593
|
-
*/
|
594
|
-
function emitCommentsEnter(comments) {
|
595
|
-
emitComments(comments, commentLocsEnter, "Comment");
|
596
|
-
}
|
597
|
-
|
598
|
-
/**
|
599
|
-
* Shortcut to check and emit exit of comment nodes
|
600
|
-
* @param {ASTNode[]} comments Collection of comment nodes
|
601
|
-
* @returns {void}
|
602
|
-
*/
|
603
|
-
function emitCommentsExit(comments) {
|
604
|
-
emitComments(comments, commentLocsExit, "Comment:exit");
|
605
|
-
}
|
606
|
-
|
607
567
|
/**
|
608
568
|
* Get the severity level of a rule (0 - none, 1 - warning, 2 - error)
|
609
569
|
* Returns 0 if the rule config is not valid (an Array or a number)
|
@@ -649,8 +609,6 @@ module.exports = (function() {
|
|
649
609
|
scopeManager = null;
|
650
610
|
controller = null;
|
651
611
|
reportingConfig = [];
|
652
|
-
commentLocsEnter = [];
|
653
|
-
commentLocsExit = [];
|
654
612
|
sourceCode = null;
|
655
613
|
};
|
656
614
|
|
@@ -811,6 +769,9 @@ module.exports = (function() {
|
|
811
769
|
}
|
812
770
|
}
|
813
771
|
|
772
|
+
var eventGenerator = new NodeEventGenerator(api);
|
773
|
+
eventGenerator = new CommentEventGenerator(eventGenerator, sourceCode);
|
774
|
+
|
814
775
|
/*
|
815
776
|
* Each node has a type property. Whenever a particular type of node is found,
|
816
777
|
* an event is fired. This allows any listeners to automatically be informed
|
@@ -818,21 +779,11 @@ module.exports = (function() {
|
|
818
779
|
*/
|
819
780
|
controller.traverse(ast, {
|
820
781
|
enter: function(node, parent) {
|
821
|
-
|
822
|
-
var comments = api.getComments(node);
|
823
|
-
|
824
|
-
emitCommentsEnter(comments.leading);
|
825
782
|
node.parent = parent;
|
826
|
-
|
827
|
-
emitCommentsEnter(comments.trailing);
|
783
|
+
eventGenerator.enterNode(node);
|
828
784
|
},
|
829
785
|
leave: function(node) {
|
830
|
-
|
831
|
-
var comments = api.getComments(node);
|
832
|
-
|
833
|
-
emitCommentsExit(comments.trailing);
|
834
|
-
api.emit(node.type + ":exit", node);
|
835
|
-
emitCommentsExit(comments.leading);
|
786
|
+
eventGenerator.leaveNode(node);
|
836
787
|
}
|
837
788
|
});
|
838
789
|
|
package/lib/options.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
/**
|
2
2
|
* @fileoverview Options configuration for optionator.
|
3
3
|
* @author George Zahariev
|
4
|
+
* See LICENSE in root directory for full license.
|
4
5
|
*/
|
5
6
|
"use strict";
|
6
7
|
|
@@ -175,6 +176,12 @@ module.exports = optionator({
|
|
175
176
|
default: false,
|
176
177
|
description: "Automatically fix problems"
|
177
178
|
},
|
179
|
+
{
|
180
|
+
option: "debug",
|
181
|
+
type: "Boolean",
|
182
|
+
default: false,
|
183
|
+
description: "Output debugging information"
|
184
|
+
},
|
178
185
|
{
|
179
186
|
option: "help",
|
180
187
|
alias: "h",
|
@@ -15,7 +15,8 @@ var astUtils = require("../ast-utils");
|
|
15
15
|
//------------------------------------------------------------------------------
|
16
16
|
|
17
17
|
module.exports = function(context) {
|
18
|
-
var spaced = context.options[0] === "always"
|
18
|
+
var spaced = context.options[0] === "always",
|
19
|
+
sourceCode = context.getSourceCode();
|
19
20
|
|
20
21
|
/**
|
21
22
|
* Determines whether an option is set, relative to the spacing option.
|
@@ -111,19 +112,19 @@ module.exports = function(context) {
|
|
111
112
|
? !options.spaced : options.spaced;
|
112
113
|
|
113
114
|
if (astUtils.isTokenOnSameLine(first, second)) {
|
114
|
-
if (openingBracketMustBeSpaced && !
|
115
|
+
if (openingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(first, second)) {
|
115
116
|
reportRequiredBeginningSpace(node, first);
|
116
117
|
}
|
117
|
-
if (!openingBracketMustBeSpaced &&
|
118
|
+
if (!openingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(first, second)) {
|
118
119
|
reportNoBeginningSpace(node, first);
|
119
120
|
}
|
120
121
|
}
|
121
122
|
|
122
123
|
if (astUtils.isTokenOnSameLine(penultimate, last)) {
|
123
|
-
if (closingBracketMustBeSpaced && !
|
124
|
+
if (closingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(penultimate, last)) {
|
124
125
|
reportRequiredEndingSpace(node, last);
|
125
126
|
}
|
126
|
-
if (!closingBracketMustBeSpaced &&
|
127
|
+
if (!closingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(penultimate, last)) {
|
127
128
|
reportNoEndingSpace(node, last);
|
128
129
|
}
|
129
130
|
}
|
@@ -13,8 +13,9 @@ var util = require("../ast-utils");
|
|
13
13
|
//------------------------------------------------------------------------------
|
14
14
|
|
15
15
|
module.exports = function(context) {
|
16
|
-
var always = (context.options[0] !== "never")
|
17
|
-
|
16
|
+
var always = (context.options[0] !== "never"),
|
17
|
+
message = always ? "Requires a space" : "Unexpected space(s)",
|
18
|
+
sourceCode = context.getSourceCode();
|
18
19
|
|
19
20
|
/**
|
20
21
|
* Gets the open brace token from a given node.
|
@@ -45,7 +46,7 @@ module.exports = function(context) {
|
|
45
46
|
function isValid(left, right) {
|
46
47
|
return (
|
47
48
|
!util.isTokenOnSameLine(left, right) ||
|
48
|
-
|
49
|
+
sourceCode.isSpaceBetweenTokens(left, right) === always
|
49
50
|
);
|
50
51
|
}
|
51
52
|
|
@@ -74,9 +74,19 @@ module.exports = function(context) {
|
|
74
74
|
* @returns {boolean} `true` if the node is multiline.
|
75
75
|
*/
|
76
76
|
function isMultiline(node) {
|
77
|
+
var lastItem = getLast(node.properties || node.elements || node.specifiers);
|
78
|
+
if (!lastItem) {
|
79
|
+
return false;
|
80
|
+
}
|
81
|
+
|
77
82
|
var sourceCode = context.getSourceCode();
|
78
|
-
var
|
79
|
-
var
|
83
|
+
var penultimateToken = sourceCode.getLastToken(lastItem);
|
84
|
+
var lastToken = sourceCode.getTokenAfter(penultimateToken);
|
85
|
+
|
86
|
+
if (lastToken.value === ",") {
|
87
|
+
penultimateToken = lastToken;
|
88
|
+
lastToken = sourceCode.getTokenAfter(lastToken);
|
89
|
+
}
|
80
90
|
|
81
91
|
return lastToken.loc.end.line !== penultimateToken.loc.end.line;
|
82
92
|
}
|
@@ -85,12 +95,13 @@ module.exports = function(context) {
|
|
85
95
|
* Reports a trailing comma if it exists.
|
86
96
|
*
|
87
97
|
* @param {ASTNode} node - A node to check. Its type is one of
|
88
|
-
* ObjectExpression, ObjectPattern, ArrayExpression,
|
98
|
+
* ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
|
99
|
+
* ImportDeclaration, and ExportNamedDeclaration.
|
89
100
|
* @returns {void}
|
90
101
|
*/
|
91
102
|
function forbidTrailingComma(node) {
|
92
|
-
var lastItem = getLast(node.properties || node.elements);
|
93
|
-
if (!lastItem) {
|
103
|
+
var lastItem = getLast(node.properties || node.elements || node.specifiers);
|
104
|
+
if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {
|
94
105
|
return;
|
95
106
|
}
|
96
107
|
|
@@ -112,12 +123,13 @@ module.exports = function(context) {
|
|
112
123
|
* comma is disallowed, so report if it exists.
|
113
124
|
*
|
114
125
|
* @param {ASTNode} node - A node to check. Its type is one of
|
115
|
-
* ObjectExpression, ObjectPattern, ArrayExpression,
|
126
|
+
* ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
|
127
|
+
* ImportDeclaration, and ExportNamedDeclaration.
|
116
128
|
* @returns {void}
|
117
129
|
*/
|
118
130
|
function forceTrailingComma(node) {
|
119
|
-
var lastItem = getLast(node.properties || node.elements);
|
120
|
-
if (!lastItem) {
|
131
|
+
var lastItem = getLast(node.properties || node.elements || node.specifiers);
|
132
|
+
if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {
|
121
133
|
return;
|
122
134
|
}
|
123
135
|
if (!isTrailingCommaAllowed(node, lastItem)) {
|
@@ -141,7 +153,8 @@ module.exports = function(context) {
|
|
141
153
|
* Otherwise, reports a trailing comma if it exists.
|
142
154
|
*
|
143
155
|
* @param {ASTNode} node - A node to check. Its type is one of
|
144
|
-
* ObjectExpression, ObjectPattern, ArrayExpression,
|
156
|
+
* ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,
|
157
|
+
* ImportDeclaration, and ExportNamedDeclaration.
|
145
158
|
* @returns {void}
|
146
159
|
*/
|
147
160
|
function forceTrailingCommaIfMultiline(node) {
|
@@ -166,7 +179,9 @@ module.exports = function(context) {
|
|
166
179
|
"ObjectExpression": checkForTrailingComma,
|
167
180
|
"ObjectPattern": checkForTrailingComma,
|
168
181
|
"ArrayExpression": checkForTrailingComma,
|
169
|
-
"ArrayPattern": checkForTrailingComma
|
182
|
+
"ArrayPattern": checkForTrailingComma,
|
183
|
+
"ImportDeclaration": checkForTrailingComma,
|
184
|
+
"ExportNamedDeclaration": checkForTrailingComma
|
170
185
|
};
|
171
186
|
};
|
172
187
|
|