'use strict'; const Transform = require('stream').Transform; const gutil = require('gulp-util'); const CLIEngine = require('eslint').CLIEngine; /** * Convenience method for creating a transform stream in object mode * * @param {Function} transform - An async function that is called for each stream chunk * @param {Function} [flush] - An async function that is called before closing the stream * @returns {stream} A transform stream */ exports.transform = function(transform, flush) { if (typeof flush === 'function') { return new Transform({ objectMode: true, transform, flush }); } return new Transform({ objectMode: true, transform }); }; /** * Mimic the CLIEngine's createIgnoreResult function, * only without the ESLint CLI reference. * * @param {Object} file - file with a "path" property * @returns {Object} An ESLint report with an ignore warning */ exports.createIgnoreResult = file => { return { filePath: file.path, messages: [{ fatal: false, severity: 1, message: file.path.indexOf('node_modules/') < 0 ? 'File ignored because of .eslintignore file' : 'File ignored because it has a node_modules/** path' }], errorCount: 0, warningCount: 1 }; }; /** * Create config helper to merge various config sources * * @param {Object} options - options to migrate * @returns {Object} migrated options */ exports.migrateOptions = function migrateOptions(options) { if (typeof options === 'string') { // basic config path overload: gulpEslint('path/to/config.json') options = { configFile: options }; } return options; }; /** * Ensure that callback errors are wrapped in a gulp PluginError * * @param {Function} callback - callback to wrap * @param {Object} [value=] - A value to pass to the callback * @returns {Function} A callback to call(back) the callback */ exports.handleCallback = (callback, value) => { return err => { if (err != null && !(err instanceof gutil.PluginError)) { err = new gutil.PluginError(err.plugin || 'gulp-eslint', err, { showStack: (err.showStack !== false) }); } callback(err, value); }; }; /** * Call sync or async action and handle any thrown or async error * * @param {Function} action - Result action to call * @param {(Object|Array)} result - An ESLint result or result list * @param {Function} done - An callback for when the action is complete */ exports.tryResultAction = function(action, result, done) { try { if (action.length > 1) { // async action action.call(this, result, done); } else { // sync action action.call(this, result); done(); } } catch (error) { done(error == null ? new Error('Unknown Error') : error); } }; /** * Get first message in an ESLint result to meet a condition * * @param {Object} result - An ESLint result * @param {Function} condition - A condition function that is passed a message and returns a boolean * @returns {Object} The first message to pass the condition or null */ exports.firstResultMessage = (result, condition) => { if (!result.messages) { return null; } return result.messages.find(condition); }; /** * Determine if a message is an error * * @param {Object} message - an ESLint message * @returns {Boolean} whether the message is an error message */ function isErrorMessage(message) { const level = message.fatal ? 2 : message.severity; if (Array.isArray(level)) { return level[0] > 1; } return level > 1; } exports.isErrorMessage = isErrorMessage; /** * Increment count if message is an error * * @param {Number} count - count of errors * @param {Object} message - an ESLint message * @returns {Number} The number of errors, message included */ function countErrorMessage(count, message) { return count + isErrorMessage(message); } /** * Increment count if message is a warning * * @param {Number} count - count of warnings * @param {Object} message - an ESLint message * @returns {Number} The number of warnings, message included */ function countWarningMessage(count, message) { return count + (message.severity === 1); } /** * Filter result messages, update error and warning counts * * @param {Object} result - an ESLint result * @param {Function} [filter=isErrorMessage] - A function that evaluates what messages to keep * @returns {Object} A filtered ESLint result */ exports.filterResult = (result, filter) => { if (typeof filter !== 'function') { filter = isErrorMessage; } const messages = result.messages.filter(filter, result); return { filePath: result.filePath, messages: messages, errorCount: messages.reduce(countErrorMessage, 0), warningCount: messages.reduce(countWarningMessage, 0) }; }; /** * Resolve formatter from unknown type (accepts string or function) * * @throws TypeError thrown if unable to resolve the formatter type * @param {(String|Function)} [formatter=stylish] - A name to resolve as a formatter. If a function is provided, the same function is returned. * @returns {Function} An ESLint formatter */ exports.resolveFormatter = (formatter) => { // use ESLint to look up formatter references if (typeof formatter !== 'function') { // load formatter (module, relative to cwd, ESLint formatter) formatter = CLIEngine.getFormatter(formatter) || formatter; } return formatter; }; /** * Resolve writable * * @param {(Function|stream)} [writable=gulp-util.log] - A stream or function to resolve as a format writer * @returns {Function} A function that writes formatted messages */ exports.resolveWritable = (writable) => { if (!writable) { writable = gutil.log; } else if (typeof writable.write === 'function') { writable = writable.write.bind(writable); } return writable; }; /** * Write formatter results to writable/output * * @param {Object[]} results - A list of ESLint results * @param {Function} formatter - A function used to format ESLint results * @param {Function} writable - A function used to write formatted ESLint results */ exports.writeResults = (results, formatter, writable) => { if (!results) { results = []; } const firstResult = results.find(result => result.config); const message = formatter(results, firstResult ? firstResult.config : {}); if (writable && message != null && message !== '') { writable(message); } };