eslint 7.0.0-alpha.2 → 7.1.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +332 -0
  2. package/README.md +9 -10
  3. package/bin/eslint.js +115 -77
  4. package/conf/category-list.json +0 -1
  5. package/conf/environments.js +2 -1
  6. package/lib/api.js +2 -0
  7. package/lib/cli-engine/cascading-config-array-factory.js +16 -2
  8. package/lib/cli-engine/cli-engine.js +53 -47
  9. package/lib/cli-engine/config-array/config-array.js +30 -1
  10. package/lib/cli-engine/config-array/ignore-pattern.js +7 -1
  11. package/lib/cli-engine/config-array-factory.js +244 -235
  12. package/lib/cli.js +181 -95
  13. package/lib/eslint/eslint.js +656 -0
  14. package/lib/eslint/index.js +7 -0
  15. package/lib/init/autoconfig.js +4 -4
  16. package/lib/init/config-file.js +2 -2
  17. package/lib/init/config-initializer.js +3 -4
  18. package/lib/init/source-code-utils.js +2 -2
  19. package/lib/linter/linter.js +2 -1
  20. package/lib/linter/node-event-generator.js +2 -2
  21. package/lib/options.js +0 -1
  22. package/lib/rule-tester/rule-tester.js +132 -22
  23. package/lib/rules/accessor-pairs.js +1 -1
  24. package/lib/rules/array-callback-return.js +3 -18
  25. package/lib/rules/arrow-parens.js +19 -3
  26. package/lib/rules/block-spacing.js +19 -2
  27. package/lib/rules/callback-return.js +4 -0
  28. package/lib/rules/camelcase.js +38 -1
  29. package/lib/rules/comma-style.js +3 -8
  30. package/lib/rules/func-call-spacing.js +4 -3
  31. package/lib/rules/getter-return.js +2 -12
  32. package/lib/rules/global-require.js +4 -0
  33. package/lib/rules/handle-callback-err.js +4 -0
  34. package/lib/rules/id-blacklist.js +138 -102
  35. package/lib/rules/index.js +1 -0
  36. package/lib/rules/key-spacing.js +1 -1
  37. package/lib/rules/linebreak-style.js +8 -2
  38. package/lib/rules/max-lines-per-function.js +1 -1
  39. package/lib/rules/new-cap.js +1 -1
  40. package/lib/rules/newline-per-chained-call.js +6 -3
  41. package/lib/rules/no-alert.js +5 -3
  42. package/lib/rules/no-buffer-constructor.js +4 -0
  43. package/lib/rules/no-empty-function.js +4 -2
  44. package/lib/rules/no-eval.js +2 -1
  45. package/lib/rules/no-extra-bind.js +1 -1
  46. package/lib/rules/no-extra-boolean-cast.js +102 -23
  47. package/lib/rules/no-extra-parens.js +9 -5
  48. package/lib/rules/no-implied-eval.js +83 -101
  49. package/lib/rules/no-inner-declarations.js +31 -39
  50. package/lib/rules/no-lone-blocks.js +1 -1
  51. package/lib/rules/no-loss-of-precision.js +198 -0
  52. package/lib/rules/no-magic-numbers.js +72 -37
  53. package/lib/rules/no-mixed-requires.js +4 -0
  54. package/lib/rules/no-new-func.js +22 -19
  55. package/lib/rules/no-new-object.js +15 -3
  56. package/lib/rules/no-new-require.js +4 -0
  57. package/lib/rules/no-new-symbol.js +2 -1
  58. package/lib/rules/no-new-wrappers.js +1 -1
  59. package/lib/rules/no-obj-calls.js +24 -5
  60. package/lib/rules/no-path-concat.js +4 -0
  61. package/lib/rules/no-plusplus.js +39 -3
  62. package/lib/rules/no-process-env.js +4 -0
  63. package/lib/rules/no-process-exit.js +4 -0
  64. package/lib/rules/no-prototype-builtins.js +1 -1
  65. package/lib/rules/no-restricted-modules.js +4 -0
  66. package/lib/rules/no-sync.js +4 -0
  67. package/lib/rules/no-unexpected-multiline.js +22 -12
  68. package/lib/rules/no-useless-concat.js +1 -1
  69. package/lib/rules/one-var-declaration-per-line.js +1 -1
  70. package/lib/rules/operator-assignment.js +3 -3
  71. package/lib/rules/operator-linebreak.js +4 -16
  72. package/lib/rules/padded-blocks.js +17 -4
  73. package/lib/rules/prefer-numeric-literals.js +3 -3
  74. package/lib/rules/prefer-object-spread.js +2 -2
  75. package/lib/rules/require-await.js +1 -1
  76. package/lib/rules/rest-spread-spacing.js +3 -6
  77. package/lib/rules/semi-spacing.js +32 -8
  78. package/lib/rules/space-before-function-paren.js +5 -2
  79. package/lib/rules/template-curly-spacing.js +59 -42
  80. package/lib/rules/utils/ast-utils.js +116 -10
  81. package/lib/rules/yoda.js +101 -51
  82. package/lib/shared/relative-module-resolver.js +1 -0
  83. package/lib/shared/types.js +9 -2
  84. package/lib/source-code/source-code.js +1 -0
  85. package/messages/extend-config-missing.txt +1 -1
  86. package/messages/no-config-found.txt +1 -1
  87. package/messages/plugin-conflict.txt +7 -0
  88. package/messages/plugin-missing.txt +1 -1
  89. package/messages/whitespace-found.txt +1 -1
  90. package/package.json +27 -26
package/lib/cli.js CHANGED
@@ -17,105 +17,176 @@
17
17
 
18
18
  const fs = require("fs"),
19
19
  path = require("path"),
20
- { CLIEngine } = require("./cli-engine"),
21
- options = require("./options"),
20
+ { promisify } = require("util"),
21
+ { ESLint } = require("./eslint"),
22
+ CLIOptions = require("./options"),
22
23
  log = require("./shared/logging"),
23
24
  RuntimeInfo = require("./shared/runtime-info");
24
25
 
25
26
  const debug = require("debug")("eslint:cli");
26
27
 
28
+ //------------------------------------------------------------------------------
29
+ // Types
30
+ //------------------------------------------------------------------------------
31
+
32
+ /** @typedef {import("./eslint/eslint").ESLintOptions} ESLintOptions */
33
+ /** @typedef {import("./eslint/eslint").LintMessage} LintMessage */
34
+ /** @typedef {import("./eslint/eslint").LintResult} LintResult */
35
+
27
36
  //------------------------------------------------------------------------------
28
37
  // Helpers
29
38
  //------------------------------------------------------------------------------
30
39
 
40
+ const mkdir = promisify(fs.mkdir);
41
+ const stat = promisify(fs.stat);
42
+ const writeFile = promisify(fs.writeFile);
43
+
31
44
  /**
32
45
  * Predicate function for whether or not to apply fixes in quiet mode.
33
46
  * If a message is a warning, do not apply a fix.
34
- * @param {LintResult} lintResult The lint result.
47
+ * @param {LintMessage} message The lint result.
35
48
  * @returns {boolean} True if the lint message is an error (and thus should be
36
49
  * autofixed), false otherwise.
37
50
  */
38
- function quietFixPredicate(lintResult) {
39
- return lintResult.severity === 2;
51
+ function quietFixPredicate(message) {
52
+ return message.severity === 2;
40
53
  }
41
54
 
42
55
  /**
43
56
  * Translates the CLI options into the options expected by the CLIEngine.
44
57
  * @param {Object} cliOptions The CLI options to translate.
45
- * @returns {CLIEngineOptions} The options object for the CLIEngine.
58
+ * @returns {ESLintOptions} The options object for the CLIEngine.
46
59
  * @private
47
60
  */
48
- function translateOptions(cliOptions) {
61
+ function translateOptions({
62
+ cache,
63
+ cacheFile,
64
+ cacheLocation,
65
+ config,
66
+ env,
67
+ errorOnUnmatchedPattern,
68
+ eslintrc,
69
+ ext,
70
+ fix,
71
+ fixDryRun,
72
+ fixType,
73
+ global,
74
+ ignore,
75
+ ignorePath,
76
+ ignorePattern,
77
+ inlineConfig,
78
+ parser,
79
+ parserOptions,
80
+ plugin,
81
+ quiet,
82
+ reportUnusedDisableDirectives,
83
+ resolvePluginsRelativeTo,
84
+ rule,
85
+ rulesdir
86
+ }) {
49
87
  return {
50
- envs: cliOptions.env,
51
- extensions: cliOptions.ext,
52
- rules: cliOptions.rule,
53
- plugins: cliOptions.plugin,
54
- globals: cliOptions.global,
55
- ignore: cliOptions.ignore,
56
- ignorePath: cliOptions.ignorePath,
57
- ignorePattern: cliOptions.ignorePattern,
58
- configFile: cliOptions.config,
59
- rulePaths: cliOptions.rulesdir,
60
- useEslintrc: cliOptions.eslintrc,
61
- parser: cliOptions.parser,
62
- parserOptions: cliOptions.parserOptions,
63
- cache: cliOptions.cache,
64
- cacheFile: cliOptions.cacheFile,
65
- cacheLocation: cliOptions.cacheLocation,
66
- fix: (cliOptions.fix || cliOptions.fixDryRun) && (cliOptions.quiet ? quietFixPredicate : true),
67
- fixTypes: cliOptions.fixType,
68
- allowInlineConfig: cliOptions.inlineConfig,
69
- reportUnusedDisableDirectives: cliOptions.reportUnusedDisableDirectives,
70
- resolvePluginsRelativeTo: cliOptions.resolvePluginsRelativeTo,
71
- errorOnUnmatchedPattern: cliOptions.errorOnUnmatchedPattern
88
+ allowInlineConfig: inlineConfig,
89
+ cache,
90
+ cacheLocation: cacheLocation || cacheFile,
91
+ errorOnUnmatchedPattern,
92
+ extensions: ext,
93
+ fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
94
+ fixTypes: fixType,
95
+ ignore,
96
+ ignorePath,
97
+ overrideConfig: {
98
+ env: env && env.reduce((obj, name) => {
99
+ obj[name] = true;
100
+ return obj;
101
+ }, {}),
102
+ globals: global && global.reduce((obj, name) => {
103
+ if (name.endsWith(":true")) {
104
+ obj[name.slice(0, -5)] = "writable";
105
+ } else {
106
+ obj[name] = "readonly";
107
+ }
108
+ return obj;
109
+ }, {}),
110
+ ignorePatterns: ignorePattern,
111
+ parser,
112
+ parserOptions,
113
+ plugins: plugin,
114
+ rules: rule
115
+ },
116
+ overrideConfigFile: config,
117
+ reportUnusedDisableDirectives: reportUnusedDisableDirectives ? "error" : void 0,
118
+ resolvePluginsRelativeTo,
119
+ rulePaths: rulesdir,
120
+ useEslintrc: eslintrc
72
121
  };
73
122
  }
74
123
 
124
+ /**
125
+ * Count error messages.
126
+ * @param {LintResult[]} results The lint results.
127
+ * @returns {{errorCount:number;warningCount:number}} The number of error messages.
128
+ */
129
+ function countErrors(results) {
130
+ let errorCount = 0;
131
+ let warningCount = 0;
132
+
133
+ for (const result of results) {
134
+ errorCount += result.errorCount;
135
+ warningCount += result.warningCount;
136
+ }
137
+
138
+ return { errorCount, warningCount };
139
+ }
140
+
141
+ /**
142
+ * Check if a given file path is a directory or not.
143
+ * @param {string} filePath The path to a file to check.
144
+ * @returns {Promise<boolean>} `true` if the given path is a directory.
145
+ */
146
+ async function isDirectory(filePath) {
147
+ try {
148
+ return (await stat(filePath)).isDirectory();
149
+ } catch (error) {
150
+ if (error.code === "ENOENT" || error.code === "ENOTDIR") {
151
+ return false;
152
+ }
153
+ throw error;
154
+ }
155
+ }
156
+
75
157
  /**
76
158
  * Outputs the results of the linting.
77
- * @param {CLIEngine} engine The CLIEngine to use.
159
+ * @param {ESLint} engine The ESLint instance to use.
78
160
  * @param {LintResult[]} results The results to print.
79
161
  * @param {string} format The name of the formatter to use or the path to the formatter.
80
162
  * @param {string} outputFile The path for the output file.
81
- * @returns {boolean} True if the printing succeeds, false if not.
163
+ * @returns {Promise<boolean>} True if the printing succeeds, false if not.
82
164
  * @private
83
165
  */
84
- function printResults(engine, results, format, outputFile) {
166
+ async function printResults(engine, results, format, outputFile) {
85
167
  let formatter;
86
- let rulesMeta;
87
168
 
88
169
  try {
89
- formatter = engine.getFormatter(format);
170
+ formatter = await engine.loadFormatter(format);
90
171
  } catch (e) {
91
172
  log.error(e.message);
92
173
  return false;
93
174
  }
94
175
 
95
- const output = formatter(results, {
96
- get rulesMeta() {
97
- if (!rulesMeta) {
98
- rulesMeta = {};
99
- for (const [ruleId, rule] of engine.getRules()) {
100
- rulesMeta[ruleId] = rule.meta;
101
- }
102
- }
103
- return rulesMeta;
104
- }
105
- });
176
+ const output = formatter.format(results);
106
177
 
107
178
  if (output) {
108
179
  if (outputFile) {
109
180
  const filePath = path.resolve(process.cwd(), outputFile);
110
181
 
111
- if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
182
+ if (await isDirectory(filePath)) {
112
183
  log.error("Cannot write to output file path, it is a directory: %s", outputFile);
113
184
  return false;
114
185
  }
115
186
 
116
187
  try {
117
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
118
- fs.writeFileSync(filePath, output);
188
+ await mkdir(path.dirname(filePath), { recursive: true });
189
+ await writeFile(filePath, output);
119
190
  } catch (ex) {
120
191
  log.error("There was a problem writing the output file:\n%s", ex);
121
192
  return false;
@@ -126,7 +197,6 @@ function printResults(engine, results, format, outputFile) {
126
197
  }
127
198
 
128
199
  return true;
129
-
130
200
  }
131
201
 
132
202
  //------------------------------------------------------------------------------
@@ -143,28 +213,33 @@ const cli = {
143
213
  * Executes the CLI based on an array of arguments that is passed in.
144
214
  * @param {string|Array|Object} args The arguments to process.
145
215
  * @param {string} [text] The text to lint (used for TTY).
146
- * @returns {int} The exit code for the operation.
216
+ * @returns {Promise<number>} The exit code for the operation.
147
217
  */
148
- execute(args, text) {
218
+ async execute(args, text) {
149
219
  if (Array.isArray(args)) {
150
220
  debug("CLI args: %o", args.slice(2));
151
221
  }
152
-
153
- let currentOptions;
222
+ let options;
154
223
 
155
224
  try {
156
- currentOptions = options.parse(args);
225
+ options = CLIOptions.parse(args);
157
226
  } catch (error) {
158
227
  log.error(error.message);
159
228
  return 2;
160
229
  }
161
230
 
162
- const files = currentOptions._;
231
+ const files = options._;
163
232
  const useStdin = typeof text === "string";
164
233
 
165
- if (currentOptions.version) {
234
+ if (options.help) {
235
+ log.info(CLIOptions.generateHelp());
236
+ return 0;
237
+ }
238
+ if (options.version) {
166
239
  log.info(RuntimeInfo.version());
167
- } else if (currentOptions.envInfo) {
240
+ return 0;
241
+ }
242
+ if (options.envInfo) {
168
243
  try {
169
244
  log.info(RuntimeInfo.environment());
170
245
  return 0;
@@ -172,7 +247,9 @@ const cli = {
172
247
  log.error(err.message);
173
248
  return 2;
174
249
  }
175
- } else if (currentOptions.printConfig) {
250
+ }
251
+
252
+ if (options.printConfig) {
176
253
  if (files.length) {
177
254
  log.error("The --print-config option must be used with exactly one file name.");
178
255
  return 2;
@@ -182,58 +259,67 @@ const cli = {
182
259
  return 2;
183
260
  }
184
261
 
185
- const engine = new CLIEngine(translateOptions(currentOptions));
186
- const fileConfig = engine.getConfigForFile(currentOptions.printConfig);
262
+ const engine = new ESLint(translateOptions(options));
263
+ const fileConfig =
264
+ await engine.calculateConfigForFile(options.printConfig);
187
265
 
188
266
  log.info(JSON.stringify(fileConfig, null, " "));
189
267
  return 0;
190
- } else if (currentOptions.help || (!files.length && !useStdin)) {
191
- log.info(options.generateHelp());
192
- } else {
193
- debug(`Running on ${useStdin ? "text" : "files"}`);
194
-
195
- if (currentOptions.fix && currentOptions.fixDryRun) {
196
- log.error("The --fix option and the --fix-dry-run option cannot be used together.");
197
- return 2;
198
- }
268
+ }
199
269
 
200
- if (useStdin && currentOptions.fix) {
201
- log.error("The --fix option is not available for piped-in code; use --fix-dry-run instead.");
202
- return 2;
203
- }
270
+ debug(`Running on ${useStdin ? "text" : "files"}`);
204
271
 
205
- if (currentOptions.fixType && !currentOptions.fix && !currentOptions.fixDryRun) {
206
- log.error("The --fix-type option requires either --fix or --fix-dry-run.");
207
- return 2;
208
- }
272
+ if (options.fix && options.fixDryRun) {
273
+ log.error("The --fix option and the --fix-dry-run option cannot be used together.");
274
+ return 2;
275
+ }
276
+ if (useStdin && options.fix) {
277
+ log.error("The --fix option is not available for piped-in code; use --fix-dry-run instead.");
278
+ return 2;
279
+ }
280
+ if (options.fixType && !options.fix && !options.fixDryRun) {
281
+ log.error("The --fix-type option requires either --fix or --fix-dry-run.");
282
+ return 2;
283
+ }
209
284
 
210
- const engine = new CLIEngine(translateOptions(currentOptions));
211
- const report = useStdin ? engine.executeOnText(text, currentOptions.stdinFilename, true) : engine.executeOnFiles(files);
285
+ const engine = new ESLint(translateOptions(options));
286
+ let results;
212
287
 
213
- if (currentOptions.fix) {
214
- debug("Fix mode enabled - applying fixes");
215
- CLIEngine.outputFixes(report);
216
- }
288
+ if (useStdin) {
289
+ results = await engine.lintText(text, {
290
+ filePath: options.stdinFilename,
291
+ warnIgnored: true
292
+ });
293
+ } else {
294
+ results = await engine.lintFiles(files);
295
+ }
217
296
 
218
- if (currentOptions.quiet) {
219
- debug("Quiet mode enabled - filtering out warnings");
220
- report.results = CLIEngine.getErrorResults(report.results);
221
- }
297
+ if (options.fix) {
298
+ debug("Fix mode enabled - applying fixes");
299
+ await ESLint.outputFixes(results);
300
+ }
222
301
 
223
- if (printResults(engine, report.results, currentOptions.format, currentOptions.outputFile)) {
224
- const tooManyWarnings = currentOptions.maxWarnings >= 0 && report.warningCount > currentOptions.maxWarnings;
302
+ if (options.quiet) {
303
+ debug("Quiet mode enabled - filtering out warnings");
304
+ results = ESLint.getErrorResults(results);
305
+ }
225
306
 
226
- if (!report.errorCount && tooManyWarnings) {
227
- log.error("ESLint found too many warnings (maximum: %s).", currentOptions.maxWarnings);
228
- }
307
+ if (await printResults(engine, results, options.format, options.outputFile)) {
308
+ const { errorCount, warningCount } = countErrors(results);
309
+ const tooManyWarnings =
310
+ options.maxWarnings >= 0 && warningCount > options.maxWarnings;
229
311
 
230
- return (report.errorCount || tooManyWarnings) ? 1 : 0;
312
+ if (!errorCount && tooManyWarnings) {
313
+ log.error(
314
+ "ESLint found too many warnings (maximum: %s).",
315
+ options.maxWarnings
316
+ );
231
317
  }
232
318
 
233
- return 2;
319
+ return (errorCount || tooManyWarnings) ? 1 : 0;
234
320
  }
235
321
 
236
- return 0;
322
+ return 2;
237
323
  }
238
324
  };
239
325