Skip to content

Instantly share code, notes, and snippets.

@EWhite613
Last active August 4, 2016 21:50
Show Gist options
  • Save EWhite613/ffbf09b0b4afda46d1653b5ca8f50e99 to your computer and use it in GitHub Desktop.
Save EWhite613/ffbf09b0b4afda46d1653b5ca8f50e99 to your computer and use it in GitHub Desktop.
broccoli-lint-eslint mergeTree fix WIP
/* eslint global-require: 0, consistent-return: 0 */
const Filter = require('broccoli-persistent-filter');
const CLIEngine = require('eslint').CLIEngine;
const md5Hex = require('md5-hex');
const stringify = require('json-stable-stringify');
const path = require('path');
const chalk = require('chalk')
const escapeStringRegexp = require('escape-string-regexp');
const BUILD_DIR_REGEXP = new RegExp('(' + escapeStringRegexp(path.sep) + ')?build(' + escapeStringRegexp(path.sep) + ')?$');
const IGNORED_FILE_MESSAGE_REGEXP = /(?:File ignored by default\.)|(?:File ignored because of a matching ignore pattern\.)/;
/**
* Calculates the severity of a eslint.linter.verify result
* @param {Array} result Eslint verify result array
* @returns {Number} If the returned number is greater than 0 the result contains errors.
*/
function getResultSeverity(result) {
// count all errors
return result.reduce((previous, message) => {
if (message.fatal) {
return previous + 1;
}
if (message.severity === 2) {
return previous + 1;
}
return previous;
}, 0);
}
/**
* Ignores messages that are about ignored files as they are intended
* but we are processing a file at a time
*
* @param {Array} errors result errors
* @returns {Array} filtered errors
*/
function filterIgnoredFileMessages(errors) {
return errors.filter((error) => !IGNORED_FILE_MESSAGE_REGEXP.test(error.message));
}
/**
* Filters all ignored file messages from result object
* @param {Object} result result errors
* @returns {Object} filtered results
*/
function filterAllIgnoredFileMessages(result) {
const resultOutput = result;
resultOutput.results.forEach((resultItem) => {
resultItem.messages = filterIgnoredFileMessages(resultItem.messages);
});
return resultOutput;
}
function resolveInputDirectory(inputNode) {
if (typeof inputNode === 'string') {
return inputNode;
}
// eslint-disable-next-line no-underscore-dangle
const nodeInfo = inputNode.__broccoliGetInfo__();
if (nodeInfo.nodeType === 'source') {
return nodeInfo.sourceDirectory;
}
if (nodeInfo.inputNodes.length > 1) {
// eslint-disable-next-line max-len
// throw new Error('EslintValidationFilter can only handle one:* broccoli nodes, but part of the given input pipeline is a many:* node. (broccoli-merge-trees is an example of a many:* node) Please perform many:* operations after linting.');
console.log(chalk.red('Merged tree'), chalk.green(nodeInfo))
debugger
var array = nodeInfo.inputNodes.map(function (node){
return resolveInputDirectory(node)
})
// console.log('Merged Tree:', array)
return array
}
return resolveInputDirectory(nodeInfo.inputNodes[0]);
}
/**
* Uses the content of each file in a given tree and runs eslint validation on it.
* @param {Object} inputNode Tree from broccoli.makeTree
* @param {{config: String, rulesdir: String, format: String}} options Filter options
* @returns {EslintValidationFilter} Filter obconfig @constructor
*/
function EslintValidationFilter(inputNode, options) {
if (!(this instanceof EslintValidationFilter)) {
return new EslintValidationFilter(inputNode, options);
}
this.options = options || {};
const eslintOptions = this.options.options || {};
// default ignore:true option
if (typeof eslintOptions.ignore === 'undefined') {
eslintOptions.ignore = true;
}
// default is to persist filter output
if (typeof this.options.persist === 'undefined') {
this.options.persist = true;
}
// call base class constructor
Filter.call(this, inputNode, this.options);
// set formatter
if (typeof this.options.format === 'function') {
this.formatter = this.options.format;
} else {
// eslint-disable-next-line global-require
this.formatter = require(this.options.format || 'eslint/lib/formatters/stylish');
}
this.cli = new CLIEngine(eslintOptions);
this.eslintrc = resolveInputDirectory(inputNode);
this.testGenerator = this.options.testGenerator;
if (this.testGenerator) {
this.targetExtension = 'lint-test.js';
}
}
module.exports = EslintValidationFilter;
EslintValidationFilter.prototype = Object.create(Filter.prototype);
EslintValidationFilter.prototype.constructor = EslintValidationFilter;
EslintValidationFilter.prototype.extensions = ['js'];
EslintValidationFilter.prototype.targetExtension = 'js';
EslintValidationFilter.prototype.baseDir = function baseDir() {
return __dirname.replace(BUILD_DIR_REGEXP, '');
};
EslintValidationFilter.prototype.cacheKeyProcessString = function cacheKeyProcessString(content, relativePath) {
function functionStringifier(key, value) {
if (typeof value === 'function') {
return value.toString();
}
return value;
}
return md5Hex([
content,
relativePath,
stringify(this.options, {replacer: functionStringifier}),
stringify(this.cli.getConfigForFile(path.join(typeof this.eslintrc === 'string' ? this.eslintrc : this.eslintrc.join(), relativePath)))
]);
};
EslintValidationFilter.prototype.processString = function processString(content, relativePath) {
// verify file content
console.log(this.eslintrc, relativePath)
if (this.eslintrc.constructor === Array){
const configPaths = this.eslintrc.map(function (file){
return path.join(file, relativePath)
})
const context = this
const outputs = configPaths.map(function (configPath){
return context.cli.executeOnText(content, configPath);
})
const filteredOutputs = outputs.map(function (output){
return filterAllIgnoredFileMessages(output)
})
var toCache = {
lint: outputs,
output: content
}
if (this.testGenerator){
var results = filteredOutputs.map(function (filteredOutput){
return filteredOutput.results[0]
})
var result = {
filePath: '',
messages: [],
errorCount: 0,
warningCount: 0
}
for (var i = 0; i < results.length; i++){
result.filePath += results[i].filePath
result.messages.push.apply(result.messages, results[i].messages)
result.errorCount += results[i].errorCount
result.warningCount += results[i].warningCount
}
var messages = result.messages
console.log('Messages:\n',chalk.red(JSON.stringify(messages, null, 2)), '\nResults:\n',chalk.red(JSON.stringify(result, null, 2)))
toCache.output = this.testGenerator(relativePath, messages, result);
}
console.log(chalk.magenta(toCache.lint, toCache.output))
return toCache;
}else{
const configPath = path.join(typeof this.eslintrc === 'string' ? this.eslintrc : this.eslintrc[0], relativePath);
const output = this.cli.executeOnText(content, configPath);
const filteredOutput = filterAllIgnoredFileMessages(output);
var toCache = {
lint: output,
output: content
};
if (this.testGenerator) {
var result = filteredOutput.results[0];
var messages = result.messages;
toCache.output = this.testGenerator(relativePath, messages, result);
}
console.log(chalk.magenta(toCache.lint, toCache.output))
return toCache;
}
};
EslintValidationFilter.prototype.postProcess = function postProcess(fromCache) {
if (fromCache.lint.constructor === Array){
var lint = fromCache.lint;
var output = fromCache.output;
var context = this
lint.forEach(function (linted){
if (linted.results.length && linted.results[0].messages.length){
console.log(linted.results)
console.log('Array', context.formatter(linted.results));
if (getResultSeverity(linted.results) > 0) {
if ('throwOnError' in context.internalOptions && context.internalOptions.throwOnError === true) {
// throw error if severe messages exist
throw new Error('severe rule errors');
}
}
}
})
// for (let i = 0; i < lint.length)
console.log(output)
return {
output
}
}else {
var lint = fromCache.lint;
var output = fromCache.output;
// if verification has result
if (lint.results.length &&
lint.results[0].messages.length) {
// log formatter output
console.log(this.formatter(lint.results));
if (getResultSeverity(lint.results) > 0) {
if ('throwOnError' in this.internalOptions && this.internalOptions.throwOnError === true) {
// throw error if severe messages exist
throw new Error('severe rule errors');
}
}
}
return {
output
};
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment