260 lines
6.4 KiB
JavaScript
260 lines
6.4 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
var Checker = require( "jscs" ),
|
||
|
jscsConfig = require( "jscs/lib/cli-config" ),
|
||
|
|
||
|
_ = require( "lodash" ),
|
||
|
hooker = require( "hooker" );
|
||
|
|
||
|
exports.init = function( grunt ) {
|
||
|
|
||
|
// Task specific options
|
||
|
var taskOptions = [ "config", "force", "reporter", "reporterOutput" ];
|
||
|
|
||
|
/**
|
||
|
* Default reporter
|
||
|
* @private
|
||
|
* @param {errorsCollection} errorsCollection
|
||
|
*/
|
||
|
function defaultReporter( errorsCollection ) {
|
||
|
errorsCollection.forEach(function( errors ) {
|
||
|
if ( !errors.isEmpty() ) {
|
||
|
errors.getErrorList().forEach(function( error ) {
|
||
|
grunt.log.writeln( errors.explainError( error, true ) );
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create new instance of jscs Checker module
|
||
|
* @constructor
|
||
|
* @param {Object} options
|
||
|
* @return {JSCS}
|
||
|
*/
|
||
|
function JSCS( options ) {
|
||
|
this.checker = new Checker();
|
||
|
this.options = options;
|
||
|
this._reporter = null;
|
||
|
|
||
|
this.checker.registerDefaultRules();
|
||
|
this.checker.configure( this.getConfig() );
|
||
|
|
||
|
this.registerReporter( options.reporter );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see Checker#execute
|
||
|
*/
|
||
|
JSCS.prototype.execute = function( path ) {
|
||
|
var run = this.checker.execute( path );
|
||
|
|
||
|
run.fail(function( error ) {
|
||
|
grunt.warn( error );
|
||
|
});
|
||
|
|
||
|
return run;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Get config
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
JSCS.prototype.getConfig = function() {
|
||
|
var configOption = this.options.config,
|
||
|
config = this.findConfig(),
|
||
|
options = this.getOptions();
|
||
|
|
||
|
// If the config option is null, but we have inline options,
|
||
|
// we'll only use them as our config.
|
||
|
if ( configOption == null && !_.isEmpty( options ) ) {
|
||
|
config = options;
|
||
|
|
||
|
} else {
|
||
|
_.assign( config, options );
|
||
|
}
|
||
|
|
||
|
this.throwForConfig( config );
|
||
|
|
||
|
return config;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Throw if something wrong with config file or with inline options
|
||
|
* @param {Object} config
|
||
|
**/
|
||
|
JSCS.prototype.throwForConfig = function( config ) {
|
||
|
var configOption = this.options.config;
|
||
|
|
||
|
if ( _.isEmpty( config ) ) {
|
||
|
if ( configOption && typeof configOption === "string" ) {
|
||
|
if ( grunt.file.exists( configOption ) ) {
|
||
|
grunt.fatal( "\"" + configOption + "\" config is empty" );
|
||
|
|
||
|
} else {
|
||
|
grunt.fatal( "The config file \"" + configOption + "\" was not found" );
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
grunt.fatal( "Neither config file nor grunt options were defined" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Read config file
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
JSCS.prototype.findConfig = function() {
|
||
|
var config = this.options && this.options.config;
|
||
|
|
||
|
// If falsy value different than undefined was given, we'll return empty object
|
||
|
if ( !config && config != null ) {
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
// `true` or null will use default jscs config loader
|
||
|
config = config === true ? null : config;
|
||
|
return jscsConfig.load( config, process.cwd() ) || {};
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Get inline options
|
||
|
* @return {Object}
|
||
|
*/
|
||
|
JSCS.prototype.getOptions = function() {
|
||
|
var option,
|
||
|
_options = {};
|
||
|
|
||
|
// Copy options to another object so this method would not be destructive
|
||
|
for ( option in this.options ) {
|
||
|
|
||
|
// If to jscs would be given a grunt task option
|
||
|
// that not defined in jscs it would throw
|
||
|
if ( !~taskOptions.indexOf( option ) ) {
|
||
|
_options[ option ] = this.options[ option ];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return _options;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Register reporter
|
||
|
* @param {String} name - name or path to the reporter
|
||
|
* @return {Reporter|null}
|
||
|
*/
|
||
|
JSCS.prototype.registerReporter = function( name ) {
|
||
|
if ( !name ) {
|
||
|
this._reporter = defaultReporter;
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
var reporter = jscsConfig.getReporter( name.toString() );
|
||
|
|
||
|
if ( reporter.writer ) {
|
||
|
this._reporter = reporter.writer;
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
grunt.fatal( "Reporter \"" + reporter.path + "\" does not exist" );
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Return reporter
|
||
|
* @return {Reporter}
|
||
|
*/
|
||
|
JSCS.prototype.getReporter = function() {
|
||
|
return this._reporter;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Set errors collection as instance property
|
||
|
* @param {errorsCollection} errorsCollection
|
||
|
*/
|
||
|
JSCS.prototype.setErrors = function( errorsCollection ) {
|
||
|
|
||
|
// Filter excluded files ("excludeFiles" option)
|
||
|
this._errors = errorsCollection.filter(function( errors ) {
|
||
|
return errors;
|
||
|
});
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Return instance errors
|
||
|
* @return {Array}
|
||
|
*/
|
||
|
JSCS.prototype.getErrors = function() {
|
||
|
return this._errors;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Count and return errors
|
||
|
* @param {errorsCollection} [errorsCollection]
|
||
|
* @return {Number}
|
||
|
*/
|
||
|
JSCS.prototype.count = function() {
|
||
|
var result = 0;
|
||
|
|
||
|
this._errors.forEach(function( errors ) {
|
||
|
result += errors.getErrorCount();
|
||
|
});
|
||
|
|
||
|
return result;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Send errors to the reporter
|
||
|
* @return {JSCS}
|
||
|
*/
|
||
|
JSCS.prototype.report = function() {
|
||
|
var options = this.options,
|
||
|
shouldHook = options.reporterOutput,
|
||
|
content = "";
|
||
|
|
||
|
if ( shouldHook ) {
|
||
|
hooker.hook( process.stdout, "write", {
|
||
|
pre: function( out ) {
|
||
|
content += out;
|
||
|
|
||
|
return hooker.preempt();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
this._result = this._reporter( this._errors );
|
||
|
|
||
|
if ( shouldHook ) {
|
||
|
grunt.file.write( options.reporterOutput, content );
|
||
|
hooker.unhook( process.stdout, "write" );
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Print number of found errors
|
||
|
* @return {JSCS}
|
||
|
*/
|
||
|
JSCS.prototype.notify = function() {
|
||
|
var errorCount = this.count();
|
||
|
|
||
|
if ( errorCount ) {
|
||
|
grunt.log.error( errorCount + " code style errors found!" );
|
||
|
|
||
|
} else {
|
||
|
grunt.log.ok( this._errors.length + " files without code style errors." );
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
return JSCS;
|
||
|
};
|