UNPKG

5.13 kBJavaScriptView Raw
1/**
2 * @fileoverview Main CLI object.
3 * @author Nicholas C. Zakas
4 */
5
6"use strict";
7
8/*
9 * The CLI object should *not* call process.exit() directly. It should only return
10 * exit codes. This allows other programs to use the CLI object and still control
11 * when the program exits.
12 */
13
14//------------------------------------------------------------------------------
15// Requirements
16//------------------------------------------------------------------------------
17
18var fs = require("fs"),
19 path = require("path"),
20
21 debug = require("debug"),
22
23 options = require("./options"),
24 CLIEngine = require("./cli-engine"),
25 mkdirp = require("mkdirp");
26
27//------------------------------------------------------------------------------
28// Helpers
29//------------------------------------------------------------------------------
30
31debug = debug("eslint:cli");
32
33/**
34 * Translates the CLI options into the options expected by the CLIEngine.
35 * @param {Object} cliOptions The CLI options to translate.
36 * @returns {CLIEngineOptions} The options object for the CLIEngine.
37 * @private
38 */
39function translateOptions(cliOptions) {
40 return {
41 envs: cliOptions.env,
42 rules: cliOptions.rule,
43 plugins: cliOptions.plugin,
44 globals: cliOptions.global,
45 ignore: cliOptions.ignore,
46 ignorePath: cliOptions.ignorePath,
47 configFile: cliOptions.config,
48 rulePaths: cliOptions.rulesdir,
49 reset: cliOptions.reset,
50 useEslintrc: cliOptions.eslintrc
51 };
52}
53
54/**
55 * Outputs the results of the linting.
56 * @param {LintResult[]} results The results to print.
57 * @param {string} format The name of the formatter to use or the path to the formatter.
58 * @param {string} outputFile The path for the output file.
59 * @param {Config} config The configuration options for the results.
60 * @returns {boolean} True if the printing succeeds, false if not.
61 * @private
62 */
63function printResults(results, format, outputFile, config) {
64 var formatter,
65 formatterPath,
66 output,
67 filePath;
68
69 if (fs.existsSync(path.resolve(process.cwd(), format))) {
70 formatterPath = path.resolve(process.cwd(), format);
71 } else {
72 formatterPath = "./formatters/" + format;
73 }
74 try {
75 formatter = require(formatterPath);
76 } catch (ex) {
77 console.error("Could not find formatter '%s'.", format);
78 return false;
79 }
80
81 output = formatter(results, config);
82
83 if (output) {
84 if (outputFile) {
85 filePath = path.resolve(process.cwd(), outputFile);
86
87 if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
88 console.error("Cannot write to output file path, it is a directory: %s", outputFile);
89 return false;
90 }
91
92 try {
93 mkdirp.sync(path.dirname(filePath));
94 fs.writeFileSync(filePath, output);
95 } catch (ex) {
96 console.error("There was a problem writing the output file:\n%s", ex);
97 return false;
98 }
99 } else {
100 console.log(output);
101 }
102 }
103
104 return true;
105
106}
107
108/**
109 * Calculates the exit code for ESLint. If there is even one error then the
110 * exit code is 1.
111 * @param {LintResult[]} results The results to calculate from.
112 * @returns {int} The exit code to use.
113 * @private
114 */
115function calculateExitCode(results) {
116 return results.some(function(result) {
117 return result.messages.some(function(message) {
118 return message.severity === 2;
119 });
120 }) ? 1 : 0;
121}
122
123//------------------------------------------------------------------------------
124// Public Interface
125//------------------------------------------------------------------------------
126
127/**
128 * Encapsulates all CLI behavior for eslint. Makes it easier to test as well as
129 * for other Node.js programs to effectively run the CLI.
130 */
131var cli = {
132
133 /**
134 * Executes the CLI based on an array of arguments that is passed in.
135 * @param {string|Array|Object} args The arguments to process.
136 * @returns {int} The exit code for the operation.
137 */
138 execute: function(args) {
139
140 var currentOptions,
141 files,
142 result,
143 engine;
144
145 try {
146 currentOptions = options.parse(args);
147 } catch (error) {
148 console.error(error.message);
149 return 1;
150 }
151
152 files = currentOptions._;
153
154 if (currentOptions.version) { // version from package.json
155
156 console.log("v" + require("../package.json").version);
157
158 } else if (currentOptions.help || !files.length) {
159
160 console.log(options.generateHelp());
161
162 } else {
163
164 engine = new CLIEngine(translateOptions(currentOptions));
165 result = engine.executeOnFiles(files);
166 if (printResults(result.results, currentOptions.format, currentOptions.outputFile)) {
167 return calculateExitCode(result.results);
168 } else {
169 return 1;
170 }
171
172 }
173
174 return 0;
175 }
176};
177
178module.exports = cli;