1 | var fs = require('fs');
|
2 |
|
3 | var Vow = require('vow');
|
4 | var Table = require('cli-table');
|
5 | var prompt = require('prompt');
|
6 | var chalk = require('chalk');
|
7 | var assign = require('lodash').assign;
|
8 |
|
9 | var Checker = require('../checker');
|
10 | var utils = require('../utils');
|
11 |
|
12 | prompt.message = '';
|
13 | prompt.delimiter = '';
|
14 | prompt.start();
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | var prompts = [
|
23 | {
|
24 | name: chalk.green('Please choose a preset number:'),
|
25 | require: true,
|
26 | pattern: /\d+/
|
27 | },
|
28 | {
|
29 | name: 'Create an (e)xception for this rule, or (f)ix the errors yourself?',
|
30 | require: true,
|
31 | pattern: /(e|f)/
|
32 | }
|
33 | ];
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | function Generator() {
|
41 | this._config = {};
|
42 | }
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 | Generator.prototype.generate = function(path) {
|
53 | var checker = getChecker();
|
54 | var _path = utils.normalizePath(path, checker.getConfiguration().getBasePath());
|
55 | var presetNames = Object.keys(checker.getConfiguration().getRegisteredPresets());
|
56 | var statsForPresets;
|
57 |
|
58 | console.log('Checking', _path, 'against the presets');
|
59 |
|
60 | return Vow
|
61 | .all(presetNames.map(this._checkAgainstPreset.bind(this, _path)))
|
62 | .then(function(resultsPerPreset) {
|
63 | statsForPresets = this._generateStatsForPresets(resultsPerPreset, presetNames);
|
64 | return statsForPresets;
|
65 | }.bind(this))
|
66 | .then(this._showErrorCounts.bind(this))
|
67 | .then(this._getUserPresetChoice.bind(this, prompts[0]))
|
68 | .then(function showViolatedRules(choiceObj) {
|
69 | var presetIndex = choiceObj[prompts[0].name] - 1;
|
70 | var presetName = statsForPresets[presetIndex].name;
|
71 |
|
72 | console.log('You chose the ' + presetName + ' preset');
|
73 |
|
74 | this._config.preset = presetName;
|
75 |
|
76 | var errorStats = getErrorsByRuleName(statsForPresets[presetIndex].errors);
|
77 |
|
78 | var violatedRuleCount = Object.keys(errorStats).length;
|
79 |
|
80 | if (!violatedRuleCount) { return this._config; }
|
81 |
|
82 | console.log(_path + ' violates ' + violatedRuleCount + ' rule' + (violatedRuleCount > 1 ? 's' : ''));
|
83 |
|
84 | var errorPrompts = generateRuleHandlingPrompts(errorStats);
|
85 |
|
86 | return this._getUserViolationChoices(errorPrompts)
|
87 | .then(this._handleViolatedRules.bind(this, errorPrompts))
|
88 | .then(function() {
|
89 | return this._config;
|
90 | }.bind(this));
|
91 | }.bind(this))
|
92 | .then(function flushConfig() {
|
93 | fs.writeFileSync(process.cwd() + '/.jscsrc', JSON.stringify(this._config, null, '\t'));
|
94 | console.log('Generated a .jscsrc configuration file in ' + process.cwd());
|
95 | }.bind(this));
|
96 | };
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 | Generator.prototype._generateStatsForPresets = function(resultsPerPreset, presetNames) {
|
105 | return resultsPerPreset.map(function(presetResults, idx) {
|
106 | var errorCollection = [].concat.apply([], presetResults);
|
107 |
|
108 | var presetStats = {
|
109 | name: presetNames[idx],
|
110 | sum: 0,
|
111 | errors: []
|
112 | };
|
113 |
|
114 | errorCollection.forEach(function(error) {
|
115 | presetStats.sum += error.getErrorCount();
|
116 | presetStats.errors = presetStats.errors.concat(error.getErrorList());
|
117 | });
|
118 |
|
119 | return presetStats;
|
120 | });
|
121 | };
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | Generator.prototype._showErrorCounts = function(statsForPresets) {
|
128 | var table = getTable();
|
129 |
|
130 | statsForPresets.forEach(function(presetStats, idx) {
|
131 | table.push([idx + 1, presetStats.name, presetStats.sum, getUniqueErrorNames(presetStats.errors).length]);
|
132 | });
|
133 |
|
134 | console.log(table.toString());
|
135 | };
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 | Generator.prototype._getUserPresetChoice = function(prompt) {
|
145 | return this._showPrompt(prompt);
|
146 | };
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 | Generator.prototype._getUserViolationChoices = function(errorPrompts) {
|
156 | return this._showPrompt(errorPrompts);
|
157 | };
|
158 |
|
159 |
|
160 | Generator.prototype._showPrompt = utils.promisify(prompt.get.bind(prompt));
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 | Generator.prototype._handleViolatedRules = function(errorPrompts, choices) {
|
168 | errorPrompts.forEach(function(errorPrompt) {
|
169 | var userChoice = choices[errorPrompt.name];
|
170 |
|
171 | if (userChoice && userChoice.toLowerCase() === 'e') {
|
172 | this._config[errorPrompt.associatedRuleName] = null;
|
173 | }
|
174 | }, this);
|
175 | };
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | Generator.prototype._checkAgainstPreset = function(path, presetName) {
|
184 | var checker = getChecker();
|
185 |
|
186 | checker.configure({preset: presetName, maxErrors: Infinity});
|
187 |
|
188 | return checker.checkPath(path);
|
189 | };
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 | function getChecker() {
|
196 | var checker = new Checker();
|
197 | checker.registerDefaultRules();
|
198 | return checker;
|
199 | }
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | function generateRuleHandlingPrompts(errors) {
|
207 |
|
208 | var violatedRuleNames = Object.keys(errors);
|
209 | violatedRuleNames.sort(function(a, b) {
|
210 | return errors[b].violations - errors[a].violations;
|
211 | });
|
212 |
|
213 | return violatedRuleNames.map(function(ruleName) {
|
214 | var violationCount = errors[ruleName].violations;
|
215 | var fileCount = Object.keys(errors[ruleName].files).length;
|
216 | var prompt = assign({}, prompts[1]);
|
217 |
|
218 | prompt.associatedRuleName = ruleName;
|
219 | prompt.name = chalk.green(ruleName) +
|
220 | ' (' + violationCount + ' violation' + (violationCount > 1 ? 's' : '') +
|
221 | ' in ' + fileCount + ' file' + (fileCount > 1 ? 's' : '') + '):\n ' +
|
222 | prompt.name;
|
223 | return prompt;
|
224 | });
|
225 | }
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 | function getErrorsByRuleName(errorsList) {
|
233 | var errors = {};
|
234 |
|
235 | errorsList.forEach(function(error) {
|
236 | var rulename = error.rule;
|
237 | errors[rulename] = errors[rulename] || {
|
238 | files: {},
|
239 | violations: 0
|
240 | };
|
241 | errors[rulename].violations += 1;
|
242 | errors[rulename].files[error.filename] = true;
|
243 | });
|
244 |
|
245 | return errors;
|
246 | }
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 | function getUniqueErrorNames(errorsList) {
|
254 | var errorNameLUT = {};
|
255 |
|
256 | errorsList.forEach(function(error) {
|
257 | errorNameLUT[error.rule] = true;
|
258 | });
|
259 |
|
260 | return Object.keys(errorNameLUT);
|
261 | }
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 | function getTable() {
|
268 | return new Table({
|
269 | chars: {
|
270 | top: '', 'top-mid': '', 'top-left': '', 'top-right': '',
|
271 | bottom: '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '',
|
272 | left: '', 'left-mid': '',
|
273 | mid: '', 'mid-mid': '',
|
274 | right: '', 'right-mid': '' ,
|
275 | middle: ' '
|
276 | },
|
277 | style: {
|
278 | 'padding-left': 0,
|
279 | 'padding-right': 0
|
280 | },
|
281 | head: ['', 'Preset', '#Errors', '#Rules']
|
282 | });
|
283 | }
|
284 |
|
285 | module.exports = Generator;
|