UNPKG

6.71 kBJavaScriptView Raw
1var vowFs = require('vow-fs');
2var Vow = require('vow');
3var StringChecker = require('./string-checker');
4var extractJs = require('./extract-js');
5var utils = require('util');
6var path = require('path');
7
8var NodeConfiguration = require('./config/node-configuration');
9
10/**
11 * Starts Code Style checking process.
12 *
13 * @name Checker
14 * @see StringChecker constructor
15 */
16var Checker = function() {
17 StringChecker.apply(this, arguments);
18};
19
20utils.inherits(Checker, StringChecker);
21
22/**
23 * Loads configuration from JS Object. Activates and configures required rules.
24 *
25 * @param {Object} config
26 */
27Checker.prototype.configure = function(config) {
28 StringChecker.prototype.configure.call(this, config);
29
30 this._fileExtensions = this._configuration.getFileExtensions();
31};
32
33/**
34 * Execute checker depending on config value either checks or checks and fixes
35 *
36 * @see Checker#checkPath/Checker#fixPath
37 */
38Checker.prototype.execute = function() {
39 var method = this._configuration.getFix() === true ? this.fixPath : this.checkPath;
40
41 return method.apply(this, arguments);
42};
43
44/**
45 * Checks single file.
46 *
47 * @param {String} path
48 * @returns {Promise.<Errors>}
49 */
50Checker.prototype.checkFile = function(path) {
51 if (this._configuration.isFileExcluded(path)) {
52 return Vow.resolve(null);
53 }
54
55 return vowFs.read(path, 'utf8').then(function(data) {
56 return this.checkString(data, path);
57 }, this);
58};
59
60/**
61 * Fixes single file.
62 *
63 * @param {String} path
64 * @returns {Promise.<Errors>}
65 */
66Checker.prototype.fixFile = function(path) {
67 if (this._configuration.isFileExcluded(path)) {
68 return Vow.resolve(null);
69 }
70
71 return vowFs.read(path, 'utf8').then(function(data) {
72 var result = this.fixString(data, path);
73 return vowFs.write(path, result.output).then(function() {
74 return result.errors;
75 });
76 }, this);
77};
78
79/**
80 * Extract JavaScript from file.
81 *
82 * @param {String} path
83 * @returns {Promise.<Errors>}
84 */
85Checker.prototype.extractFile = function(path) {
86 if (this._configuration.isFileExcluded(path)) {
87 return Vow.resolve(null);
88 }
89
90 if (!this._configuration.shouldExtractFile(path)) {
91 return Vow.resolve(null);
92 }
93
94 return vowFs.read(path, 'utf8').then(function(data) {
95 var result = extractJs(path, data);
96
97 result.sources.forEach(function(script) {
98 this.checkString(script.source, path).getErrorList().forEach(function(error) {
99 error.line += script.line;
100 error.column += script.offset;
101 result.addError(error);
102 });
103 }, this);
104
105 return result.errors;
106 }, this);
107};
108
109/**
110 * Checks directory recursively.
111 *
112 * @param {String} path
113 * @returns {Promise.<Error[]>}
114 */
115Checker.prototype.checkDirectory = function(path) {
116 return this._processDirectory(path, this.checkFile.bind(this));
117};
118
119/**
120 * Checks directory or file.
121 *
122 * @param {String} path
123 * @returns {Promise.<Error[]>}
124 */
125Checker.prototype.checkPath = function(path) {
126 return this._processPath(path, this.checkFile.bind(this));
127};
128
129/**
130 * Fixes directory or file.
131 *
132 * @param {String} path
133 * @returns {Promise.<Error[]>}
134 */
135Checker.prototype.fixPath = function(path) {
136 return this._processPath(path, this.fixFile.bind(this));
137};
138
139/**
140 * Processes directory recursively.
141 *
142 * @param {String} path
143 * @param {Function} fileHandler
144 * @returns {Promise.<Error[]>}
145 */
146Checker.prototype._processDirectory = function(path, fileHandler) {
147 return vowFs.listDir(path).then(function(filenames) {
148 return Vow.all(filenames.map(function(filename) {
149 var fullname = path + '/' + filename;
150
151 if (this._configuration.isFileExcluded(fullname)) {
152 return [];
153 }
154
155 return vowFs.stat(fullname).then(function(stat) {
156 if (stat.isDirectory()) {
157 return this._processDirectory(fullname, fileHandler);
158 }
159
160 if (!this._hasCorrectExtension(fullname)) {
161 if (!this._configuration.shouldExtractFile(fullname)) {
162 return [];
163 }
164
165 return this.extractFile(fullname);
166 }
167
168 return fileHandler(fullname);
169 }, this);
170 }, this)).then(function(results) {
171 return [].concat.apply([], results);
172 });
173 }, this);
174};
175
176/**
177 * Processes directory or file.
178 *
179 * @param {String} path
180 * @param {Function} fileHandler
181 * @returns {Promise.<Error[]>}
182 */
183Checker.prototype._processPath = function(path, fileHandler) {
184 path = path.replace(/\/$/, '');
185
186 return vowFs.exists(path).then(function(exists) {
187 if (!exists) {
188 throw new Error('Path ' + path + ' was not found.');
189 }
190
191 return vowFs.stat(path).then(function(stat) {
192 if (stat.isDirectory()) {
193 return this._processDirectory(path, fileHandler);
194 }
195
196 return fileHandler(path).then(function(errors) {
197 if (errors) {
198 return [errors];
199 }
200
201 return [];
202 });
203 }, this);
204 }, this);
205};
206
207/**
208 * Checks stdin for input
209 *
210 * @returns {Promise}
211 */
212Checker.prototype.checkStdin = function() {
213 return this._processStdin(this.checkString.bind(this));
214};
215
216/**
217 * Fixes stdin input
218 *
219 * @returns {Promise}
220 */
221Checker.prototype.fixStdin = function() {
222 return this._processStdin(this.fixString.bind(this));
223};
224
225/**
226 *
227 * @param {Function} stdinHandler
228 * @returns {Promise}
229 */
230Checker.prototype._processStdin = function(stdinHandler) {
231 var stdInput = [];
232 var deferred = Vow.defer();
233
234 process.stdin.setEncoding('utf8');
235
236 process.stdin.on('data', function(chunk) {
237 stdInput.push(chunk);
238 });
239
240 process.stdin.on('end', function() {
241 deferred.resolve(stdinHandler(stdInput.join('')));
242 });
243
244 return deferred.promise();
245};
246
247/**
248 * Returns true if the file extension matches a file extension to process.
249 *
250 * @returns {Boolean}
251 */
252Checker.prototype._hasCorrectExtension = function(testPath) {
253 var extension = path.extname(testPath).toLowerCase();
254 var basename = path.basename(testPath).toLowerCase();
255
256 return !(
257 this._fileExtensions.indexOf(extension) < 0 &&
258 this._fileExtensions.indexOf(basename) < 0 &&
259 this._fileExtensions.indexOf('*') < 0
260 );
261};
262
263/**
264 * Returns new configuration instance.
265 *
266 * @protected
267 * @returns {NodeConfiguration}
268 */
269Checker.prototype._createConfiguration = function() {
270 return new NodeConfiguration();
271};
272
273module.exports = Checker;