eslint 0.22.0 → 0.24.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.
Files changed (201) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +111 -95
  3. package/bin/eslint.js +41 -41
  4. package/conf/environments.js +87 -81
  5. package/conf/eslint.json +186 -179
  6. package/lib/api.js +13 -12
  7. package/lib/cli-engine.js +441 -451
  8. package/lib/cli.js +196 -196
  9. package/lib/config-initializer.js +145 -145
  10. package/lib/config-validator.js +110 -110
  11. package/lib/config.js +428 -416
  12. package/lib/eslint.js +1072 -1073
  13. package/lib/file-finder.js +167 -167
  14. package/lib/formatters/checkstyle.js +68 -68
  15. package/lib/formatters/compact.js +53 -53
  16. package/lib/formatters/jslint-xml.js +40 -40
  17. package/lib/formatters/junit.js +63 -63
  18. package/lib/formatters/stylish.js +90 -90
  19. package/lib/formatters/tap.js +86 -86
  20. package/lib/ignored-paths.js +137 -137
  21. package/lib/load-rules.js +39 -39
  22. package/lib/options.js +132 -126
  23. package/lib/rule-context.js +107 -107
  24. package/lib/rules/accessor-pairs.js +65 -65
  25. package/lib/rules/array-bracket-spacing.js +180 -0
  26. package/lib/rules/block-scoped-var.js +339 -320
  27. package/lib/rules/brace-style.js +228 -228
  28. package/lib/rules/camelcase.js +111 -111
  29. package/lib/rules/comma-dangle.js +67 -64
  30. package/lib/rules/comma-spacing.js +191 -191
  31. package/lib/rules/comma-style.js +195 -195
  32. package/lib/rules/complexity.js +94 -94
  33. package/lib/rules/computed-property-spacing.js +144 -0
  34. package/lib/rules/consistent-return.js +75 -75
  35. package/lib/rules/consistent-this.js +119 -119
  36. package/lib/rules/constructor-super.js +108 -0
  37. package/lib/rules/curly.js +109 -109
  38. package/lib/rules/default-case.js +66 -66
  39. package/lib/rules/dot-location.js +63 -63
  40. package/lib/rules/dot-notation.js +119 -119
  41. package/lib/rules/eol-last.js +38 -38
  42. package/lib/rules/eqeqeq.js +96 -96
  43. package/lib/rules/func-names.js +45 -45
  44. package/lib/rules/func-style.js +49 -49
  45. package/lib/rules/generator-star-spacing.js +104 -87
  46. package/lib/rules/generator-star.js +76 -76
  47. package/lib/rules/global-strict.js +49 -49
  48. package/lib/rules/guard-for-in.js +32 -32
  49. package/lib/rules/handle-callback-err.js +81 -124
  50. package/lib/rules/indent.js +486 -486
  51. package/lib/rules/key-spacing.js +325 -325
  52. package/lib/rules/linebreak-style.js +44 -44
  53. package/lib/rules/lines-around-comment.js +228 -160
  54. package/lib/rules/max-depth.js +89 -89
  55. package/lib/rules/max-len.js +76 -76
  56. package/lib/rules/max-nested-callbacks.js +73 -73
  57. package/lib/rules/max-params.js +45 -45
  58. package/lib/rules/max-statements.js +61 -61
  59. package/lib/rules/new-cap.js +224 -224
  60. package/lib/rules/new-parens.js +29 -29
  61. package/lib/rules/newline-after-var.js +127 -127
  62. package/lib/rules/no-alert.js +153 -153
  63. package/lib/rules/no-array-constructor.js +31 -31
  64. package/lib/rules/no-bitwise.js +57 -57
  65. package/lib/rules/no-caller.js +29 -29
  66. package/lib/rules/no-catch-shadow.js +52 -52
  67. package/lib/rules/no-comma-dangle.js +45 -45
  68. package/lib/rules/no-cond-assign.js +123 -123
  69. package/lib/rules/no-console.js +27 -27
  70. package/lib/rules/no-constant-condition.js +73 -73
  71. package/lib/rules/no-continue.js +23 -23
  72. package/lib/rules/no-control-regex.js +58 -58
  73. package/lib/rules/no-debugger.js +22 -22
  74. package/lib/rules/no-delete-var.js +25 -25
  75. package/lib/rules/no-div-regex.js +27 -27
  76. package/lib/rules/no-dupe-args.js +89 -85
  77. package/lib/rules/no-dupe-keys.js +43 -43
  78. package/lib/rules/no-duplicate-case.js +67 -67
  79. package/lib/rules/no-else-return.js +125 -125
  80. package/lib/rules/no-empty-character-class.js +43 -43
  81. package/lib/rules/no-empty-class.js +45 -45
  82. package/lib/rules/no-empty-label.js +27 -27
  83. package/lib/rules/no-empty.js +49 -49
  84. package/lib/rules/no-eq-null.js +29 -29
  85. package/lib/rules/no-eval.js +26 -26
  86. package/lib/rules/no-ex-assign.js +42 -42
  87. package/lib/rules/no-extend-native.js +103 -103
  88. package/lib/rules/no-extra-bind.js +81 -81
  89. package/lib/rules/no-extra-boolean-cast.js +71 -71
  90. package/lib/rules/no-extra-parens.js +368 -355
  91. package/lib/rules/no-extra-semi.js +70 -23
  92. package/lib/rules/no-extra-strict.js +86 -86
  93. package/lib/rules/no-fallthrough.js +97 -97
  94. package/lib/rules/no-floating-decimal.js +30 -30
  95. package/lib/rules/no-func-assign.js +83 -83
  96. package/lib/rules/no-implied-eval.js +76 -76
  97. package/lib/rules/no-inline-comments.js +49 -49
  98. package/lib/rules/no-inner-declarations.js +78 -78
  99. package/lib/rules/no-invalid-regexp.js +53 -53
  100. package/lib/rules/no-irregular-whitespace.js +135 -135
  101. package/lib/rules/no-iterator.js +28 -28
  102. package/lib/rules/no-label-var.js +64 -64
  103. package/lib/rules/no-labels.js +44 -44
  104. package/lib/rules/no-lone-blocks.js +106 -27
  105. package/lib/rules/no-lonely-if.js +30 -30
  106. package/lib/rules/no-loop-func.js +58 -58
  107. package/lib/rules/no-mixed-requires.js +165 -165
  108. package/lib/rules/no-mixed-spaces-and-tabs.js +74 -74
  109. package/lib/rules/no-multi-spaces.js +119 -119
  110. package/lib/rules/no-multi-str.js +43 -43
  111. package/lib/rules/no-multiple-empty-lines.js +98 -98
  112. package/lib/rules/no-native-reassign.js +62 -62
  113. package/lib/rules/no-negated-in-lhs.js +25 -25
  114. package/lib/rules/no-nested-ternary.js +24 -24
  115. package/lib/rules/no-new-func.js +25 -25
  116. package/lib/rules/no-new-object.js +25 -25
  117. package/lib/rules/no-new-require.js +25 -25
  118. package/lib/rules/no-new-wrappers.js +26 -26
  119. package/lib/rules/no-new.js +27 -27
  120. package/lib/rules/no-obj-calls.js +28 -28
  121. package/lib/rules/no-octal-escape.js +39 -39
  122. package/lib/rules/no-octal.js +25 -25
  123. package/lib/rules/no-param-reassign.js +87 -87
  124. package/lib/rules/no-path-concat.js +39 -39
  125. package/lib/rules/no-plusplus.js +24 -24
  126. package/lib/rules/no-process-env.js +30 -30
  127. package/lib/rules/no-process-exit.js +33 -33
  128. package/lib/rules/no-proto.js +28 -28
  129. package/lib/rules/no-redeclare.js +68 -68
  130. package/lib/rules/no-regex-spaces.js +35 -35
  131. package/lib/rules/no-reserved-keys.js +56 -56
  132. package/lib/rules/no-restricted-modules.js +85 -85
  133. package/lib/rules/no-return-assign.js +53 -24
  134. package/lib/rules/no-script-url.js +34 -34
  135. package/lib/rules/no-self-compare.js +29 -29
  136. package/lib/rules/no-sequences.js +94 -94
  137. package/lib/rules/no-shadow-restricted-names.js +51 -51
  138. package/lib/rules/no-shadow.js +181 -136
  139. package/lib/rules/no-space-before-semi.js +98 -98
  140. package/lib/rules/no-spaced-func.js +37 -37
  141. package/lib/rules/no-sparse-arrays.js +33 -33
  142. package/lib/rules/no-sync.js +30 -30
  143. package/lib/rules/no-ternary.js +24 -24
  144. package/lib/rules/no-this-before-super.js +144 -0
  145. package/lib/rules/no-throw-literal.js +33 -33
  146. package/lib/rules/no-trailing-spaces.js +74 -63
  147. package/lib/rules/no-undef-init.js +28 -28
  148. package/lib/rules/no-undef.js +92 -92
  149. package/lib/rules/no-undefined.js +27 -27
  150. package/lib/rules/no-underscore-dangle.js +73 -73
  151. package/lib/rules/no-unexpected-multiline.js +58 -0
  152. package/lib/rules/no-unneeded-ternary.js +48 -48
  153. package/lib/rules/no-unreachable.js +98 -98
  154. package/lib/rules/no-unused-expressions.js +76 -76
  155. package/lib/rules/no-unused-vars.js +252 -250
  156. package/lib/rules/no-use-before-define.js +105 -105
  157. package/lib/rules/no-var.js +26 -26
  158. package/lib/rules/no-void.js +28 -28
  159. package/lib/rules/no-warning-comments.js +102 -102
  160. package/lib/rules/no-with.js +22 -22
  161. package/lib/rules/no-wrap-func.js +65 -65
  162. package/lib/rules/object-curly-spacing.js +231 -206
  163. package/lib/rules/object-shorthand.js +74 -73
  164. package/lib/rules/one-var.js +311 -304
  165. package/lib/rules/operator-assignment.js +118 -118
  166. package/lib/rules/operator-linebreak.js +114 -114
  167. package/lib/rules/padded-blocks.js +98 -98
  168. package/lib/rules/prefer-const.js +91 -0
  169. package/lib/rules/quote-props.js +72 -72
  170. package/lib/rules/quotes.js +92 -92
  171. package/lib/rules/radix.js +41 -41
  172. package/lib/rules/semi-spacing.js +167 -167
  173. package/lib/rules/semi.js +136 -136
  174. package/lib/rules/sort-vars.js +49 -49
  175. package/lib/rules/space-after-function-name.js +49 -49
  176. package/lib/rules/space-after-keywords.js +82 -82
  177. package/lib/rules/space-before-blocks.js +91 -91
  178. package/lib/rules/space-before-function-paren.js +139 -139
  179. package/lib/rules/space-before-function-parentheses.js +139 -139
  180. package/lib/rules/space-in-brackets.js +305 -305
  181. package/lib/rules/space-in-parens.js +281 -281
  182. package/lib/rules/space-infix-ops.js +106 -106
  183. package/lib/rules/space-return-throw-case.js +38 -38
  184. package/lib/rules/space-unary-ops.js +124 -133
  185. package/lib/rules/spaced-comment.js +143 -0
  186. package/lib/rules/spaced-line-comment.js +89 -89
  187. package/lib/rules/strict.js +242 -242
  188. package/lib/rules/use-isnan.js +26 -26
  189. package/lib/rules/valid-jsdoc.js +215 -215
  190. package/lib/rules/valid-typeof.js +42 -42
  191. package/lib/rules/vars-on-top.js +115 -115
  192. package/lib/rules/wrap-iife.js +48 -48
  193. package/lib/rules/wrap-regex.js +38 -38
  194. package/lib/rules/yoda.js +242 -225
  195. package/lib/rules.js +88 -88
  196. package/lib/timing.js +109 -109
  197. package/lib/token-store.js +201 -201
  198. package/lib/util/traverse.js +105 -105
  199. package/lib/util.js +125 -85
  200. package/package.json +6 -6
  201. package/CHANGELOG.md +0 -1638
package/lib/cli-engine.js CHANGED
@@ -1,451 +1,441 @@
1
- /**
2
- * @fileoverview Main CLI object.
3
- * @author Nicholas C. Zakas
4
- * @copyright 2014 Nicholas C. Zakas. All rights reserved.
5
- */
6
-
7
- "use strict";
8
-
9
- /*
10
- * The CLI object should *not* call process.exit() directly. It should only return
11
- * exit codes. This allows other programs to use the CLI object and still control
12
- * when the program exits.
13
- */
14
-
15
- //------------------------------------------------------------------------------
16
- // Requirements
17
- //------------------------------------------------------------------------------
18
-
19
- var fs = require("fs"),
20
- path = require("path"),
21
-
22
- assign = require("object-assign"),
23
- debug = require("debug"),
24
-
25
- rules = require("./rules"),
26
- eslint = require("./eslint"),
27
- traverse = require("./util/traverse"),
28
- IgnoredPaths = require("./ignored-paths"),
29
- Config = require("./config"),
30
- util = require("./util");
31
-
32
- //------------------------------------------------------------------------------
33
- // Typedefs
34
- //------------------------------------------------------------------------------
35
-
36
- /**
37
- * The options to configure a CLI engine with.
38
- * @typedef {Object} CLIEngineOptions
39
- * @property {string} configFile The configuration file to use.
40
- * @property {boolean} reset True disables all default rules and environments.
41
- * @property {boolean|object} baseConfig Base config object. False disables all default rules and environments.
42
- * @property {boolean} ignore False disables use of .eslintignore.
43
- * @property {string[]} rulePaths An array of directories to load custom rules from.
44
- * @property {boolean} useEslintrc False disables looking for .eslintrc
45
- * @property {string[]} envs An array of environments to load.
46
- * @property {string[]} globals An array of global variables to declare.
47
- * @property {string[]} extensions An array of file extensions to check.
48
- * @property {Object<string,*>} rules An object of rules to use.
49
- * @property {string} ignorePath The ignore file to use instead of .eslintignore.
50
- */
51
-
52
- /**
53
- * A linting warning or error.
54
- * @typedef {Object} LintMessage
55
- * @property {string} message The message to display to the user.
56
- */
57
-
58
- /**
59
- * A linting result.
60
- * @typedef {Object} LintResult
61
- * @property {string} filePath The path to the file that was linted.
62
- * @property {LintMessage[]} messages All of the messages for the result.
63
- */
64
-
65
- //------------------------------------------------------------------------------
66
- // Private
67
- //------------------------------------------------------------------------------
68
-
69
-
70
- var defaultOptions = {
71
- configFile: null,
72
- reset: false,
73
- baseConfig: require(path.resolve(__dirname, "..", "conf", "eslint.json")),
74
- rulePaths: [],
75
- useEslintrc: true,
76
- envs: [],
77
- globals: [],
78
- rules: {},
79
- extensions: [".js"],
80
- ignore: true,
81
- ignorePath: null
82
- },
83
- loadedPlugins = Object.create(null);
84
-
85
- //------------------------------------------------------------------------------
86
- // Helpers
87
- //------------------------------------------------------------------------------
88
-
89
- debug = debug("eslint:cli-engine");
90
-
91
- /**
92
- * Load the given plugins if they are not loaded already.
93
- * @param {string[]} pluginNames An array of plugin names which should be loaded.
94
- * @returns {void}
95
- */
96
- function loadPlugins(pluginNames) {
97
- if (pluginNames) {
98
- pluginNames.forEach(function (pluginName) {
99
- var pluginNamespace = util.getNamespace(pluginName),
100
- pluginNameWithoutNamespace = util.removeNameSpace(pluginName),
101
- pluginNameWithoutPrefix = util.removePluginPrefix(pluginNameWithoutNamespace),
102
- plugin;
103
-
104
- if (!loadedPlugins[pluginNameWithoutPrefix]) {
105
- debug("Load plugin " + pluginNameWithoutPrefix);
106
-
107
- plugin = require(pluginNamespace + util.PLUGIN_NAME_PREFIX + pluginNameWithoutPrefix);
108
- // if this plugin has rules, import them
109
- if (plugin.rules) {
110
- rules.import(plugin.rules, pluginNameWithoutPrefix);
111
- }
112
-
113
- loadedPlugins[pluginNameWithoutPrefix] = plugin;
114
- }
115
- });
116
- }
117
- }
118
-
119
- /**
120
- * It will calculate the error and warning count for collection of messages per file
121
- * @param {Object[]} messages - Collection of messages
122
- * @returns {Object} Contains the stats
123
- * @private
124
- */
125
- function calculateStatsPerFile(messages) {
126
- return messages.reduce(function(stat, message) {
127
- if (message.fatal || message.severity === 2) {
128
- stat.errorCount++;
129
- } else {
130
- stat.warningCount++;
131
- }
132
- return stat;
133
- }, {
134
- errorCount: 0,
135
- warningCount: 0
136
- });
137
- }
138
-
139
- /**
140
- * It will calculate the error and warning count for collection of results from all files
141
- * @param {Object[]} results - Collection of messages from all the files
142
- * @returns {Object} Contains the stats
143
- * @private
144
- */
145
- function calculateStatsPerRun(results) {
146
- return results.reduce(function(stat, result) {
147
- stat.errorCount += result.errorCount;
148
- stat.warningCount += result.warningCount;
149
- return stat;
150
- }, {
151
- errorCount: 0,
152
- warningCount: 0
153
- });
154
- }
155
-
156
- /**
157
- * Processes an individual file using ESLint. Files used here are known to
158
- * exist, so no need to check that here.
159
- * @param {string} filename The filename of the file being checked.
160
- * @param {Object} configHelper The configuration options for ESLint.
161
- * @returns {Result} The results for linting on this file.
162
- * @private
163
- */
164
- function processFile(filename, configHelper) {
165
-
166
- // clear all existing settings for a new file
167
- eslint.reset();
168
-
169
- var filePath = path.resolve(filename),
170
- config,
171
- text,
172
- messages,
173
- stats,
174
- fileExtension = path.extname(filename),
175
- processor;
176
-
177
- debug("Linting " + filePath);
178
- config = configHelper.getConfig(filePath);
179
- loadPlugins(config.plugins);
180
- text = fs.readFileSync(path.resolve(filename), "utf8");
181
-
182
- for (var plugin in loadedPlugins) {
183
- if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) {
184
- processor = loadedPlugins[plugin].processors[fileExtension];
185
- break;
186
- }
187
- }
188
-
189
- if (processor) {
190
- var parsedBlocks = processor.preprocess(text, filename);
191
- var unprocessedMessages = [];
192
- parsedBlocks.forEach(function(block) {
193
- unprocessedMessages.push(eslint.verify(block, config, filename));
194
- });
195
- messages = processor.postprocess(unprocessedMessages, filename);
196
- } else {
197
- messages = eslint.verify(text, config, filename);
198
- }
199
-
200
- stats = calculateStatsPerFile(messages);
201
-
202
- return {
203
- filePath: filename,
204
- messages: messages,
205
- errorCount: stats.errorCount,
206
- warningCount: stats.warningCount
207
- };
208
- }
209
-
210
- /**
211
- * Processes an source code using ESLint.
212
- * @param {string} text The source code to check.
213
- * @param {Object} configHelper The configuration options for ESLint.
214
- * @param {string} filename An optional string representing the texts filename.
215
- * @returns {Result} The results for linting on this text.
216
- * @private
217
- */
218
- function processText(text, configHelper, filename) {
219
-
220
- // clear all existing settings for a new file
221
- eslint.reset();
222
-
223
- var config,
224
- messages,
225
- stats;
226
-
227
- filename = filename || "<text>";
228
- debug("Linting " + filename);
229
- config = configHelper.getConfig();
230
- loadPlugins(config.plugins);
231
- messages = eslint.verify(text, config, filename);
232
-
233
- stats = calculateStatsPerFile(messages);
234
-
235
- return {
236
- filePath: filename,
237
- messages: messages,
238
- errorCount: stats.errorCount,
239
- warningCount: stats.warningCount
240
- };
241
- }
242
-
243
- /**
244
- * Returns result with warning by ignore settings
245
- * @param {string} filePath File path of checked code
246
- * @returns {Result} Result with single warning
247
- * @private
248
- */
249
- function createIgnoreResult(filePath) {
250
- return {
251
- filePath: filePath,
252
- messages: [
253
- {
254
- fatal: false,
255
- severity: 1,
256
- message: "File ignored because of your .eslintignore file. Use --no-ignore to override."
257
- }
258
- ],
259
- errorCount: 0,
260
- warningCount: 1
261
- };
262
- }
263
-
264
- //------------------------------------------------------------------------------
265
- // Public Interface
266
- //------------------------------------------------------------------------------
267
-
268
- /**
269
- * Creates a new instance of the core CLI engine.
270
- * @param {CLIEngineOptions} options The options for this instance.
271
- * @constructor
272
- */
273
- function CLIEngine(options) {
274
-
275
- /**
276
- * Stored options for this instance
277
- * @type {Object}
278
- */
279
- this.options = assign(Object.create(defaultOptions), options || {});
280
-
281
- // load in additional rules
282
- if (this.options.rulePaths) {
283
- this.options.rulePaths.forEach(function(rulesdir) {
284
- debug("Loading rules from " + rulesdir);
285
- rules.load(rulesdir);
286
- });
287
- }
288
- }
289
-
290
- CLIEngine.prototype = {
291
-
292
- constructor: CLIEngine,
293
-
294
- /**
295
- * Add a plugin by passing it's configuration
296
- * @param {string} name Name of the plugin.
297
- * @param {Object} pluginobject Plugin configuration object.
298
- * @returns {void}
299
- */
300
- addPlugin: function(name, pluginobject) {
301
- var pluginNameWithoutPrefix = util.removePluginPrefix(util.removeNameSpace(name));
302
- if (pluginobject.rules) {
303
- rules.import(pluginobject.rules, pluginNameWithoutPrefix);
304
- }
305
- loadedPlugins[pluginNameWithoutPrefix] = pluginobject;
306
- },
307
-
308
- /**
309
- * Executes the current configuration on an array of file and directory names.
310
- * @param {string[]} files An array of file and directory names.
311
- * @returns {Object} The results for all files that were linted.
312
- */
313
- executeOnFiles: function(files) {
314
-
315
- var results = [],
316
- processed = [],
317
- options = this.options,
318
- configHelper = new Config(options),
319
- ignoredPaths = IgnoredPaths.load(options),
320
- exclude = ignoredPaths.contains.bind(ignoredPaths),
321
- stats;
322
-
323
- traverse({
324
- files: files,
325
- extensions: options.extensions,
326
- exclude: options.ignore ? exclude : false
327
- }, function(filename) {
328
-
329
- debug("Processing " + filename);
330
-
331
- processed.push(filename);
332
- results.push(processFile(filename, configHelper));
333
- });
334
-
335
- // only warn for files explicitly passed on the command line
336
- if (options.ignore) {
337
- files.forEach(function(file) {
338
- if (fs.statSync(path.resolve(file)).isFile() && processed.indexOf(file) === -1) {
339
- results.push(createIgnoreResult(file));
340
- }
341
- });
342
- }
343
-
344
- stats = calculateStatsPerRun(results);
345
-
346
- return {
347
- results: results,
348
- errorCount: stats.errorCount,
349
- warningCount: stats.warningCount
350
- };
351
- },
352
-
353
- /**
354
- * Executes the current configuration on text.
355
- * @param {string} text A string of JavaScript code to lint.
356
- * @param {string} filename An optional string representing the texts filename.
357
- * @returns {Object} The results for the linting.
358
- */
359
- executeOnText: function(text, filename) {
360
-
361
- var configHelper = new Config(this.options),
362
- results = [],
363
- stats,
364
- options = this.options,
365
- ignoredPaths = IgnoredPaths.load(options),
366
- exclude = ignoredPaths.contains.bind(ignoredPaths);
367
-
368
- if (filename && options.ignore && exclude(filename)) {
369
- results.push(createIgnoreResult(filename));
370
- } else {
371
- results.push(processText(text, configHelper, filename));
372
- }
373
-
374
- stats = calculateStatsPerRun(results);
375
-
376
- return {
377
- results: results,
378
- errorCount: stats.errorCount,
379
- warningCount: stats.warningCount
380
- };
381
- },
382
-
383
- /**
384
- * Returns a configuration object for the given file based on the CLI options.
385
- * This is the same logic used by the ESLint CLI executable to determine
386
- * configuration for each file it processes.
387
- * @param {string} filePath The path of the file to retrieve a config object for.
388
- * @returns {Object} A configuration object for the file.
389
- */
390
- getConfigForFile: function(filePath) {
391
- var configHelper = new Config(this.options);
392
- return configHelper.getConfig(filePath);
393
- },
394
-
395
- /**
396
- * Checks if a given path is ignored by ESLint.
397
- * @param {string} filePath The path of the file to check.
398
- * @returns {boolean} Whether or not the given path is ignored.
399
- */
400
- isPathIgnored: function (filePath) {
401
- var ignoredPaths;
402
-
403
- if (this.options.ignore) {
404
- ignoredPaths = IgnoredPaths.load(this.options);
405
- return ignoredPaths.contains(filePath);
406
- }
407
-
408
- return false;
409
- },
410
-
411
- /**
412
- * Returns the formatter representing the given format or null if no formatter
413
- * with the given name can be found.
414
- * @param {string} [format] The name of the format to load or the path to a
415
- * custom formatter.
416
- * @returns {Function} The formatter function or null if not found.
417
- */
418
- getFormatter: function(format) {
419
-
420
- var formatterPath;
421
-
422
- // default is stylish
423
- format = format || "stylish";
424
-
425
- // only strings are valid formatters
426
- if (typeof format === "string") {
427
-
428
- // replace \ with / for Windows compatibility
429
- format = format.replace(/\\/g, "/");
430
-
431
- // if there's a slash, then it's a file
432
- if (format.indexOf("/") > -1) {
433
- formatterPath = path.resolve(process.cwd(), format);
434
- } else {
435
- formatterPath = "./formatters/" + format;
436
- }
437
-
438
- try {
439
- return require(formatterPath);
440
- } catch (ex) {
441
- return null;
442
- }
443
-
444
- } else {
445
- return null;
446
- }
447
- }
448
-
449
- };
450
-
451
- module.exports = CLIEngine;
1
+ /**
2
+ * @fileoverview Main CLI object.
3
+ * @author Nicholas C. Zakas
4
+ * @copyright 2014 Nicholas C. Zakas. All rights reserved.
5
+ */
6
+
7
+ "use strict";
8
+
9
+ /*
10
+ * The CLI object should *not* call process.exit() directly. It should only return
11
+ * exit codes. This allows other programs to use the CLI object and still control
12
+ * when the program exits.
13
+ */
14
+
15
+ //------------------------------------------------------------------------------
16
+ // Requirements
17
+ //------------------------------------------------------------------------------
18
+
19
+ var fs = require("fs"),
20
+ path = require("path"),
21
+
22
+ assign = require("object-assign"),
23
+ debug = require("debug"),
24
+
25
+ rules = require("./rules"),
26
+ eslint = require("./eslint"),
27
+ traverse = require("./util/traverse"),
28
+ IgnoredPaths = require("./ignored-paths"),
29
+ Config = require("./config"),
30
+ util = require("./util"),
31
+ validator = require("./config-validator");
32
+
33
+ //------------------------------------------------------------------------------
34
+ // Typedefs
35
+ //------------------------------------------------------------------------------
36
+
37
+ /**
38
+ * The options to configure a CLI engine with.
39
+ * @typedef {Object} CLIEngineOptions
40
+ * @property {string} configFile The configuration file to use.
41
+ * @property {boolean} reset True disables all default rules and environments.
42
+ * @property {boolean|object} baseConfig Base config object. False disables all default rules and environments.
43
+ * @property {boolean} ignore False disables use of .eslintignore.
44
+ * @property {string[]} rulePaths An array of directories to load custom rules from.
45
+ * @property {boolean} useEslintrc False disables looking for .eslintrc
46
+ * @property {string[]} envs An array of environments to load.
47
+ * @property {string[]} globals An array of global variables to declare.
48
+ * @property {string[]} extensions An array of file extensions to check.
49
+ * @property {Object<string,*>} rules An object of rules to use.
50
+ * @property {string} ignorePath The ignore file to use instead of .eslintignore.
51
+ */
52
+
53
+ /**
54
+ * A linting warning or error.
55
+ * @typedef {Object} LintMessage
56
+ * @property {string} message The message to display to the user.
57
+ */
58
+
59
+ /**
60
+ * A linting result.
61
+ * @typedef {Object} LintResult
62
+ * @property {string} filePath The path to the file that was linted.
63
+ * @property {LintMessage[]} messages All of the messages for the result.
64
+ */
65
+
66
+ //------------------------------------------------------------------------------
67
+ // Private
68
+ //------------------------------------------------------------------------------
69
+
70
+
71
+ var defaultOptions = {
72
+ configFile: null,
73
+ reset: false,
74
+ baseConfig: require(path.resolve(__dirname, "..", "conf", "eslint.json")),
75
+ rulePaths: [],
76
+ useEslintrc: true,
77
+ envs: [],
78
+ globals: [],
79
+ rules: {},
80
+ extensions: [".js"],
81
+ ignore: true,
82
+ ignorePath: null
83
+ },
84
+ loadedPlugins = Object.create(null);
85
+
86
+ //------------------------------------------------------------------------------
87
+ // Helpers
88
+ //------------------------------------------------------------------------------
89
+
90
+ debug = debug("eslint:cli-engine");
91
+
92
+ /**
93
+ * Load the given plugins if they are not loaded already.
94
+ * @param {string[]} pluginNames An array of plugin names which should be loaded.
95
+ * @returns {void}
96
+ */
97
+ function loadPlugins(pluginNames) {
98
+ if (pluginNames) {
99
+ pluginNames.forEach(function (pluginName) {
100
+ var pluginNamespace = util.getNamespace(pluginName),
101
+ pluginNameWithoutNamespace = util.removeNameSpace(pluginName),
102
+ pluginNameWithoutPrefix = util.removePluginPrefix(pluginNameWithoutNamespace),
103
+ plugin;
104
+
105
+ if (!loadedPlugins[pluginNameWithoutPrefix]) {
106
+ debug("Load plugin " + pluginNameWithoutPrefix);
107
+
108
+ plugin = require(pluginNamespace + util.PLUGIN_NAME_PREFIX + pluginNameWithoutPrefix);
109
+ // if this plugin has rules, import them
110
+ if (plugin.rules) {
111
+ rules.import(plugin.rules, pluginNameWithoutPrefix);
112
+ }
113
+
114
+ loadedPlugins[pluginNameWithoutPrefix] = plugin;
115
+ }
116
+ });
117
+ }
118
+ }
119
+
120
+ /**
121
+ * It will calculate the error and warning count for collection of messages per file
122
+ * @param {Object[]} messages - Collection of messages
123
+ * @returns {Object} Contains the stats
124
+ * @private
125
+ */
126
+ function calculateStatsPerFile(messages) {
127
+ return messages.reduce(function(stat, message) {
128
+ if (message.fatal || message.severity === 2) {
129
+ stat.errorCount++;
130
+ } else {
131
+ stat.warningCount++;
132
+ }
133
+ return stat;
134
+ }, {
135
+ errorCount: 0,
136
+ warningCount: 0
137
+ });
138
+ }
139
+
140
+ /**
141
+ * It will calculate the error and warning count for collection of results from all files
142
+ * @param {Object[]} results - Collection of messages from all the files
143
+ * @returns {Object} Contains the stats
144
+ * @private
145
+ */
146
+ function calculateStatsPerRun(results) {
147
+ return results.reduce(function(stat, result) {
148
+ stat.errorCount += result.errorCount;
149
+ stat.warningCount += result.warningCount;
150
+ return stat;
151
+ }, {
152
+ errorCount: 0,
153
+ warningCount: 0
154
+ });
155
+ }
156
+
157
+ /**
158
+ * Processes an source code using ESLint.
159
+ * @param {string} text The source code to check.
160
+ * @param {Object} configHelper The configuration options for ESLint.
161
+ * @param {string} filename An optional string representing the texts filename.
162
+ * @returns {Result} The results for linting on this text.
163
+ * @private
164
+ */
165
+ function processText(text, configHelper, filename) {
166
+
167
+ // clear all existing settings for a new file
168
+ eslint.reset();
169
+
170
+ var filePath,
171
+ config,
172
+ messages,
173
+ stats,
174
+ fileExtension = path.extname(filename),
175
+ processor;
176
+
177
+ if (filename) {
178
+ filePath = path.resolve(filename);
179
+ }
180
+
181
+ filename = filename || "<text>";
182
+ debug("Linting " + filename);
183
+ config = configHelper.getConfig(filePath);
184
+ loadPlugins(config.plugins);
185
+
186
+ for (var plugin in loadedPlugins) {
187
+ if (loadedPlugins[plugin].processors && Object.keys(loadedPlugins[plugin].processors).indexOf(fileExtension) >= 0) {
188
+ processor = loadedPlugins[plugin].processors[fileExtension];
189
+ break;
190
+ }
191
+ }
192
+
193
+ if (processor) {
194
+ var parsedBlocks = processor.preprocess(text, filename);
195
+ var unprocessedMessages = [];
196
+ parsedBlocks.forEach(function(block) {
197
+ unprocessedMessages.push(eslint.verify(block, config, filename));
198
+ });
199
+ messages = processor.postprocess(unprocessedMessages, filename);
200
+ } else {
201
+ messages = eslint.verify(text, config, filename);
202
+ }
203
+
204
+ stats = calculateStatsPerFile(messages);
205
+
206
+ return {
207
+ filePath: filename,
208
+ messages: messages,
209
+ errorCount: stats.errorCount,
210
+ warningCount: stats.warningCount
211
+ };
212
+ }
213
+
214
+ /**
215
+ * Processes an individual file using ESLint. Files used here are known to
216
+ * exist, so no need to check that here.
217
+ * @param {string} filename The filename of the file being checked.
218
+ * @param {Object} configHelper The configuration options for ESLint.
219
+ * @returns {Result} The results for linting on this file.
220
+ * @private
221
+ */
222
+ function processFile(filename, configHelper) {
223
+
224
+ var text = fs.readFileSync(path.resolve(filename), "utf8");
225
+
226
+ return processText(text, configHelper, filename);
227
+ }
228
+
229
+ /**
230
+ * Returns result with warning by ignore settings
231
+ * @param {string} filePath File path of checked code
232
+ * @returns {Result} Result with single warning
233
+ * @private
234
+ */
235
+ function createIgnoreResult(filePath) {
236
+ return {
237
+ filePath: filePath,
238
+ messages: [
239
+ {
240
+ fatal: false,
241
+ severity: 1,
242
+ message: "File ignored because of your .eslintignore file. Use --no-ignore to override."
243
+ }
244
+ ],
245
+ errorCount: 0,
246
+ warningCount: 1
247
+ };
248
+ }
249
+
250
+ //------------------------------------------------------------------------------
251
+ // Public Interface
252
+ //------------------------------------------------------------------------------
253
+
254
+ /**
255
+ * Creates a new instance of the core CLI engine.
256
+ * @param {CLIEngineOptions} options The options for this instance.
257
+ * @constructor
258
+ */
259
+ function CLIEngine(options) {
260
+
261
+ /**
262
+ * Stored options for this instance
263
+ * @type {Object}
264
+ */
265
+ this.options = assign(Object.create(defaultOptions), options || {});
266
+
267
+ // load in additional rules
268
+ if (this.options.rulePaths) {
269
+ this.options.rulePaths.forEach(function(rulesdir) {
270
+ debug("Loading rules from " + rulesdir);
271
+ rules.load(rulesdir);
272
+ });
273
+ }
274
+
275
+ Object.keys(this.options.rules || {}).forEach(function(name) {
276
+ validator.validateRuleOptions(name, this.options.rules[name], "CLI");
277
+ }.bind(this));
278
+ }
279
+
280
+ CLIEngine.prototype = {
281
+
282
+ constructor: CLIEngine,
283
+
284
+ /**
285
+ * Add a plugin by passing it's configuration
286
+ * @param {string} name Name of the plugin.
287
+ * @param {Object} pluginobject Plugin configuration object.
288
+ * @returns {void}
289
+ */
290
+ addPlugin: function(name, pluginobject) {
291
+ var pluginNameWithoutPrefix = util.removePluginPrefix(util.removeNameSpace(name));
292
+ if (pluginobject.rules) {
293
+ rules.import(pluginobject.rules, pluginNameWithoutPrefix);
294
+ }
295
+ loadedPlugins[pluginNameWithoutPrefix] = pluginobject;
296
+ },
297
+
298
+ /**
299
+ * Executes the current configuration on an array of file and directory names.
300
+ * @param {string[]} files An array of file and directory names.
301
+ * @returns {Object} The results for all files that were linted.
302
+ */
303
+ executeOnFiles: function(files) {
304
+
305
+ var results = [],
306
+ processed = [],
307
+ options = this.options,
308
+ configHelper = new Config(options),
309
+ ignoredPaths = IgnoredPaths.load(options),
310
+ exclude = ignoredPaths.contains.bind(ignoredPaths),
311
+ stats;
312
+
313
+ traverse({
314
+ files: files,
315
+ extensions: options.extensions,
316
+ exclude: options.ignore ? exclude : false
317
+ }, function(filename) {
318
+
319
+ debug("Processing " + filename);
320
+
321
+ processed.push(filename);
322
+ results.push(processFile(filename, configHelper));
323
+ });
324
+
325
+ // only warn for files explicitly passed on the command line
326
+ if (options.ignore) {
327
+ files.forEach(function(file) {
328
+ if (fs.statSync(path.resolve(file)).isFile() && processed.indexOf(file) === -1) {
329
+ results.push(createIgnoreResult(file));
330
+ }
331
+ });
332
+ }
333
+
334
+ stats = calculateStatsPerRun(results);
335
+
336
+ return {
337
+ results: results,
338
+ errorCount: stats.errorCount,
339
+ warningCount: stats.warningCount
340
+ };
341
+ },
342
+
343
+ /**
344
+ * Executes the current configuration on text.
345
+ * @param {string} text A string of JavaScript code to lint.
346
+ * @param {string} filename An optional string representing the texts filename.
347
+ * @returns {Object} The results for the linting.
348
+ */
349
+ executeOnText: function(text, filename) {
350
+
351
+ var results = [],
352
+ stats,
353
+ options = this.options,
354
+ configHelper = new Config(options),
355
+ ignoredPaths = IgnoredPaths.load(options),
356
+ exclude = ignoredPaths.contains.bind(ignoredPaths);
357
+
358
+ if (filename && options.ignore && exclude(filename)) {
359
+ results.push(createIgnoreResult(filename));
360
+ } else {
361
+ results.push(processText(text, configHelper, filename));
362
+ }
363
+
364
+ stats = calculateStatsPerRun(results);
365
+
366
+ return {
367
+ results: results,
368
+ errorCount: stats.errorCount,
369
+ warningCount: stats.warningCount
370
+ };
371
+ },
372
+
373
+ /**
374
+ * Returns a configuration object for the given file based on the CLI options.
375
+ * This is the same logic used by the ESLint CLI executable to determine
376
+ * configuration for each file it processes.
377
+ * @param {string} filePath The path of the file to retrieve a config object for.
378
+ * @returns {Object} A configuration object for the file.
379
+ */
380
+ getConfigForFile: function(filePath) {
381
+ var configHelper = new Config(this.options);
382
+ return configHelper.getConfig(filePath);
383
+ },
384
+
385
+ /**
386
+ * Checks if a given path is ignored by ESLint.
387
+ * @param {string} filePath The path of the file to check.
388
+ * @returns {boolean} Whether or not the given path is ignored.
389
+ */
390
+ isPathIgnored: function (filePath) {
391
+ var ignoredPaths;
392
+
393
+ if (this.options.ignore) {
394
+ ignoredPaths = IgnoredPaths.load(this.options);
395
+ return ignoredPaths.contains(filePath);
396
+ }
397
+
398
+ return false;
399
+ },
400
+
401
+ /**
402
+ * Returns the formatter representing the given format or null if no formatter
403
+ * with the given name can be found.
404
+ * @param {string} [format] The name of the format to load or the path to a
405
+ * custom formatter.
406
+ * @returns {Function} The formatter function or null if not found.
407
+ */
408
+ getFormatter: function(format) {
409
+
410
+ var formatterPath;
411
+
412
+ // default is stylish
413
+ format = format || "stylish";
414
+
415
+ // only strings are valid formatters
416
+ if (typeof format === "string") {
417
+
418
+ // replace \ with / for Windows compatibility
419
+ format = format.replace(/\\/g, "/");
420
+
421
+ // if there's a slash, then it's a file
422
+ if (format.indexOf("/") > -1) {
423
+ formatterPath = path.resolve(process.cwd(), format);
424
+ } else {
425
+ formatterPath = "./formatters/" + format;
426
+ }
427
+
428
+ try {
429
+ return require(formatterPath);
430
+ } catch (ex) {
431
+ return null;
432
+ }
433
+
434
+ } else {
435
+ return null;
436
+ }
437
+ }
438
+
439
+ };
440
+
441
+ module.exports = CLIEngine;