diff --git a/src/features-provider/features-provider.js b/src/features-provider/features-provider.js index bd68ceee..5b274761 100644 --- a/src/features-provider/features-provider.js +++ b/src/features-provider/features-provider.js @@ -1,4 +1,4 @@ -const {flatMap, uniq} = require('../utils/generic'); +const {flatMap, flatten, uniq} = require('../utils/generic'); const glob = require('glob'); const fs = require('fs'); const path = require('path'); @@ -50,6 +50,17 @@ const reportFailure = (pattern) => { }); }; +const getFileNames = (globOptions) => (pattern) => { + const globPatterns = getGlobPatterns(pattern, '**/*.feature'); + const fileNames = filterFeatures(flatMap((globPattern) => { + return glob.sync(globPattern, globOptions); + })(globPatterns)); + if (fileNames.length === 0) { + return reportFailure(pattern); + } + return Promise.resolve(fileNames); +}; + class FeatureProvider { constructor(args, {ignore = defaults.ignore, cwd}) { this.args = args; @@ -65,23 +76,9 @@ class FeatureProvider { ignore: getIgnorePatterns(ignore, cwd), cwd, }; - let resultPromise = Promise.resolve([]); - for (let index = 0; index < patterns.length; ++index) { - const pattern = patterns[index]; - const globPatterns = getGlobPatterns(pattern, '**/*.feature'); - const fileNames = filterFeatures(flatMap((globPattern) => { - return glob.sync(globPattern, globOptions); - })(globPatterns)); - if (fileNames.length === 0) { - return reportFailure(pattern); - } - resultPromise = resultPromise.then((result) => { - result.push(...fileNames); - return result; - }); - } - - return resultPromise.then((files) => parseFileList(files)); + return Promise.all(patterns.map(getFileNames(globOptions))) + .then(flatten) + .then(parseFileList); } } diff --git a/src/linter/index.js b/src/linter/index.js index 75e1a21a..dba7a4ec 100644 --- a/src/linter/index.js +++ b/src/linter/index.js @@ -1,22 +1,22 @@ +const {flatten} = require('../utils/generic'); + const sortByLine = (errors) => errors.sort((a, b) => { return a.location.line - b.location.line; }); +const lintFileWith = (fileLinter, rules) => (file) => { + return fileLinter.lint(file, rules).then((fileErrors) => { + return fileErrors.length > 0 ? [{ + message: file.path, + errors: sortByLine(fileErrors), + }] : []; + }); +}; + const lintFiles = (files, rules, fileLinter) => { - const outputPromise = files.reduce((errorsPromise, file) => { - return errorsPromise.then((errors) => { - return fileLinter.lint(file, rules).then((fileErrors) => { - if (fileErrors.length > 0) { - const fileBlob = { - message: file.path, - errors: sortByLine(fileErrors), - }; - errors.push(fileBlob); - } - return errors; - }); - }); - }, Promise.resolve([])); + const lintFile = lintFileWith(fileLinter, rules); + const outputPromise = Promise.all(files.map(lintFile)) + .then(flatten); return outputPromise.then((output) => { return output.length > 0 diff --git a/src/rules-parser.js b/src/rules-parser.js index 429951cb..19d4e4f2 100644 --- a/src/rules-parser.js +++ b/src/rules-parser.js @@ -1,4 +1,5 @@ const enablingSettings = ['on', 'off']; +const {flatten} = require('./utils/generic'); const RuleCommand = require('./rule-command'); function isValidEnablingSetting(enablingSetting) { @@ -59,35 +60,56 @@ function normalizeRule(rules, config, ruleName) { } } -function RuleParser(rules) { - this.rules = rules; -} +const getRuleResultPromises = (rules, config) => { + return Object.keys(config).map((ruleName) => { + return normalizeRule(rules, config, ruleName); + }); +}; -const append = (result, array) => { - result.push(...array); - return result; +const getErrors = (prom) => { + return prom.then( + (result) => [], + (errors) => (errors) + ); }; -RuleParser.prototype.parse = function(config) { - const {rules} = this; - const resultPromise = Object.keys(config).reduce(function(resultPromise, ruleName) { - const rulePromise = normalizeRule(rules, config, ruleName); - return resultPromise.then( - (result) => rulePromise.then( - (rules) => append(result, rules), - (errors) => Promise.reject(errors) - ), - (errorResults) => rulePromise.then( - (rules) => Promise.reject(errorResults), - (errorRules) => Promise.reject(append(errorResults, errorRules)) - ) - ); - }, Promise.resolve([])); - return resultPromise.catch((errors) => Promise.reject({ - type: 'config-error', - message: 'Error(s) in configuration file:', - errors, - })); +const filterRules = (rulePromises) => { + return Promise.all(rulePromises).then( + flatten, + () => [] + ); }; +const filterErrors = (rulePromises) => { + return Promise.all(rulePromises.map(getErrors)) + .then(flatten) + .then((errors) => { + return errors.length > 0 ? Promise.reject(errors) : []; + }); +}; + +const buildConfigErrors = (errors) => ({ + type: 'config-error', + message: 'Error(s) in configuration file:', + errors, +}); + +class RuleParser { + constructor(rules) { + this.rules = rules; + } + + parse(config) { + const {rules} = this; + const promises = getRuleResultPromises(rules, config); + const rulesPromise = filterRules(promises); + const errorsPromise = filterErrors(promises); + return Promise.all([rulesPromise, errorsPromise]) + .then( + ([rules]) => rules, + (errors) => Promise.reject(buildConfigErrors(errors)) + ); + } +} + module.exports = RuleParser; diff --git a/src/utils/generic.js b/src/utils/generic.js index 98bcd558..0153c96e 100644 --- a/src/utils/generic.js +++ b/src/utils/generic.js @@ -37,6 +37,8 @@ const applyAfter = (appendedCheck) => (check) => applyOver([ const uniq = (array) => [...new Set(array)]; +const flatten = flatMap((items) => items); + module.exports = { append, applyAfter, @@ -44,6 +46,7 @@ module.exports = { applyWith, compose, flatMap, + flatten, intoArray, reduce, uniq,