biofriction-wp-theme/node_modules/gulp-phpcs/index.js

261 lines
8.1 KiB
JavaScript

var util = require('util'),
path = require('path'),
PluginError = require('plugin-error'),
through = require('through2'),
which = require('which'),
spawn = require('child_process').spawn;
/**
* Builds shell command for PHP Code Sniffer according to specified options.
*
* @param {Object} opts List of PHP Code Sniffer options.
* @returns {Object} Object with "bin" and "args" keys that specify shell command.
*/
var buildCommand = function(opts) {
var args = [];
var commandOptions = {};
if (opts.hasOwnProperty('standard')) {
args.push('--standard=' + opts.standard);
}
if (opts.hasOwnProperty('severity')) {
args.push('--severity=' + parseInt(opts.severity));
}
if (opts.hasOwnProperty('warningSeverity')) {
args.push('--warning-severity=' + parseInt(opts.warningSeverity));
}
if (opts.hasOwnProperty('errorSeverity')) {
args.push('--error-severity=' + parseInt(opts.errorSeverity));
}
if (opts.hasOwnProperty('encoding')) {
args.push('--encoding=' + opts.encoding);
}
if (opts.hasOwnProperty('report')) {
args.push('--report=' + opts.report);
}
if (opts.hasOwnProperty('showSniffCode') && opts.showSniffCode) {
args.push('-s');
}
var useSniffs = opts.hasOwnProperty('sniffs') &&
Array.isArray(opts.sniffs) &&
opts.sniffs.length !== 0;
if (useSniffs) {
args.push('--sniffs=' + opts.sniffs.join(','));
}
var useExclude = opts.hasOwnProperty('exclude') &&
Array.isArray(opts.exclude) &&
opts.exclude.length !== 0;
if (useExclude) {
args.push('--exclude=' + opts.exclude.join(','));
}
var useIgnore = opts.hasOwnProperty('ignore') &&
Array.isArray(opts.ignore) &&
opts.ignore.length !== 0;
if (useIgnore) {
args.push('--ignore=' + opts.ignore.join(','));
}
if (opts.hasOwnProperty('colors') && opts.colors) {
args.push('--colors');
}
if (opts.hasOwnProperty('cwd') && opts.cwd) {
commandOptions.cwd = opts.cwd;
}
// Finally specify the file is streamed on stdin.
args.push('-');
return {
bin: opts.bin || 'phpcs',
args: args,
options: commandOptions
};
};
/**
* Resolves real path of the command.
*
* The results are cached inside of the function.
*
* @type Function
* @param {String} bin A command which should be resolved.
* @param {Function} callback A function which will be called once the command
* is resolved or a error occurs. The error object (or null) is passed as the
* first argument. The real path of the command is passed as the second argument.
* If the command is not found the second argument is boolean false.
*/
var resolveCommand = (function(){
// Closure is used here to cache resolved commands.
var cache = {};
return function(bin, callback) {
if (cache.hasOwnProperty(bin)) {
return callback(null, cache[bin]);
}
var normalizedBin = path.normalize(bin.replace(/[\\/]/g, path.sep));
which(normalizedBin, function(err, resolved) {
if (err) {
if (err.code !== 'ENOENT') {
// Something is totally wrong. Let the outer code know.
return callback(err);
}
// The command is just not found.
cache[bin] = false;
return callback(null, false);
}
cache[bin] = resolved;
callback(null, resolved);
});
};
})();
/**
* Runs Code Sniffer shell command.
*
* @param {String} bin Shell command (without arguments) that should be performed
* @param {Array} args List of arguments that should be passed to the Shell command.
* @param {Array} options Options to be passed into the child_process.spawn.
* @param {Object} file A file from Gulp pipeline that should be sniffed.
* @param {Function} callback A function which will be called when Code Sniffer is
* done or an error occurs. It will receive three arguments: error instance, exit
* code and output of the Code Sniffer. The last two arguments will be passed in
* only if there was no error during execution.
*/
var runCodeSniffer = function(bin, args, options, file, callback) {
resolveCommand(bin, function(error, resolvedBin) {
if (error) {
// A real error occurs during command resolving. We can do nothing
// here, so just let the developer know.
var wrappedError = new Error(util.format(
'Cannot resolve real path of "%s"',
bin
));
wrappedError.originalError = error;
return callback(wrappedError);
}
if (resolvedBin === false) {
// The bin is not found. Let the developer know about it.
return callback(new Error(util.format('Cannot find "%s"', bin)));
}
// A buffer for PHPCS stdout stream.
var stdout = '';
// child_process.spawn is used instead of child_process.exec because of
// its flexibility.
var phpcs = spawn(resolvedBin, args, options);
phpcs.on('error', function(error) {
callback(error);
});
phpcs.on('close', function(code) {
callback(null, code, stdout);
});
phpcs.stdin.on('error', function(error) {
// Just ignore this event because an error (with more
// detailed description) should also be emitted at spawned
// process instance.
});
phpcs.stdout.on('data', function(data) {
// Just buffer data from stdout to use it later.
stdout += data.toString();
});
// Detect line endings like it's done in PHPCS
var matches = /\r\n?|\n/.exec(file.contents.toString()),
eol = matches ? matches[0] : '\n';
// Pass the file name to Code Sniffer. This is needed to
// get the correct error message from Code Sniffer.
phpcs.stdin.write('phpcs_input_file: ' + file.path + eol);
// Pass content of the file as STDIN to Code Sniffer
phpcs.stdin.write(file.contents);
phpcs.stdin.end();
});
};
var phpcsPlugin = function(options) {
var command = buildCommand(options || {});
return through.obj(function(file, enc, callback) {
var stream = this;
if (file.isNull()) {
stream.push(file);
callback();
return;
}
if (file.isStream()) {
stream.emit('error', new PluginError('gulp-phpcs', 'Streams are not supported'));
callback();
return;
}
runCodeSniffer(command.bin, command.args, command.options, file, function(runError, exitCode, output) {
if (runError) {
// Something is totally wrong. It seems that execution of Code Sniffer
// failed (not because of non-zero exit code of PHPCS).
stream.emit('error', new PluginError('gulp-phpcs', runError));
callback();
return;
}
if (exitCode > 2) {
// On codding style problems Code Sniffer should exists with "1" or "2" code.
// All other non-zero exit codes should be treated as Code Sniffer errors.
var phpcsError = new PluginError('gulp-phpcs', 'Execution of Code Sniffer Failed');
phpcsError.stdout = output;
stream.emit('error', phpcsError);
callback();
return;
}
var report = {
error: false,
output: ''
};
if ((exitCode === 1) || (exitCode === 2)) {
// A coding style problem is found.
// Attach report to the file to allow
// reporters do their job.
report.error = true;
report.output = output;
}
file.phpcsReport = report;
stream.push(file);
callback();
});
});
};
// Attach reporters loader to the plugin.
phpcsPlugin.reporter = require('./reporters');
module.exports = phpcsPlugin;