Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generated impacts as a part of rule descriptions #898

Merged
merged 8 commits into from
May 25, 2018
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*eslint complexity: ["error",12], max-statements: ["error", 30],
camelcase: ["error", {"properties": "never"}]*/
camelcase: ["error", {"properties": "never"}]*/
var testConfig = require('./build/test/config');

module.exports = function (grunt) {
Expand Down
114 changes: 84 additions & 30 deletions build/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ var clone = require('clone');
var dot = require('dot');
var templates = require('./templates');
var buildManual = require('./build-manual');
var entities = new (require('html-entities').AllHtmlEntities)();
var entities = new (require('html-entities').AllHtmlEntities)();

var descriptionHeaders = '| Rule ID | Description | Tags | Enabled by default |\n| :------- | :------- | :------- | :------- |\n';
var descriptionHeaders = '| Rule ID | Description | Impact | Tags | Enabled by default |\n| :------- | :------- | :------- | :------- | :------- |\n';

dot.templateSettings.strip = false;

Expand All @@ -24,10 +24,29 @@ function getLocale(grunt, options) {
}

function buildRules(grunt, options, commons, callback) {
var axeImpact = Object.freeze(['minor', 'moderate', 'serious', 'critical']); // TODO: require('../axe') does not work if grunt configure is moved after uglify, npm test breaks with undefined. Complicated grunt concurrency issue.
var locale = getLocale(grunt, options);
options.getFiles = false;
buildManual(grunt, options, commons, function (result) {

var metadata = {
rules: {},
checks: {}
};
var descriptions = [];
var tags = options.tags ? options.tags.split(/\s*,\s*/) : [];
var rules = result.rules;
var checks = result.checks;

// Translate checks
if (locale && locale.checks) {
checks.forEach(function (check) {
if (locale.checks[check.id] && check.metadata) {
check.metadata.messages = locale.checks[check.id];
}
})
}

function parseMetaData(source, propType) {
var data = source.metadata
var key = source.id || source.type
Expand Down Expand Up @@ -64,15 +83,14 @@ function buildRules(grunt, options, commons, callback) {

function getIncompleteMsg(summaries) {
var result = {};
summaries.forEach(function(summary) {
summaries.forEach(function (summary) {
if (summary.incompleteFallbackMessage) {
result = dot.template(summary.incompleteFallbackMessage).toString();
}
})
return result;
}


function replaceFunctions(string) {
return string.replace(/"(evaluate|after|gather|matches|source|commons)":\s*("[^"]+?")/g, function (m, p1, p2) {
return m.replace(p2, getSource(p2.replace(/^"|"$/g, ''), p1));
Expand All @@ -81,7 +99,6 @@ function buildRules(grunt, options, commons, callback) {
}).replace(/"(\(function \(\) {)([\s\S]+?)(}\)\(\))"/g, function (m) {
return JSON.parse(m);
});

}

function getSource(file, type) {
Expand All @@ -107,27 +124,6 @@ function buildRules(grunt, options, commons, callback) {
return v;
}

var metadata = {
rules: {},
checks: {}
};

var descriptions = [];

var tags = options.tags ? options.tags.split(/\s*,\s*/) : [];

var rules = result.rules;
var checks = result.checks;

// Translate checks
if (locale && locale.checks) {
checks.forEach(function (check) {
if (locale.checks[check.id] && check.metadata) {
check.metadata.messages = locale.checks[check.id]
}
})
}

function parseChecks(collection) {
return collection.map(function (check) {
var c = {};
Expand All @@ -145,19 +141,77 @@ function buildRules(grunt, options, commons, callback) {

return c.options === undefined ? id : c;
});
}

function parseImpactForRule(rule) {


function capitalize(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
}

function getUniqueArr(arr) {
return arr.filter(function (value, index, self) {
return self.indexOf(value) === index;
})
}

function getImpactScores(checkCollection) {
return checkCollection.reduce(function (out, check) {
var id = typeof check === 'string' ? check : check.id;
var definition = clone(findCheck(checks, id));
if (!definition) {
grunt.log.error('check ' + id + ' not found');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we stop execution and return here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure, not a blocker so leaving as is, until I read up grunt docs.

}
if (definition && definition.metadata && definition.metadata.impact) {
var impactScore = axeImpact.indexOf(definition.metadata.impact);
out.push(impactScore);
}
return out;
}, []);
}

function getScore(checkCollection, onlyHighestScore) {
var scores = getImpactScores(checkCollection);
if (scores && scores.length) {
return onlyHighestScore
? [Math.max.apply(null, scores)]
: getUniqueArr(scores);
} else {
return [];
}
}

var highestImpactForRuleTypeAny = getScore(rule.any, true);
var allUniqueImpactsForRuleTypeAll = getScore(rule.all, false);
var allUniqueImpactsForRuleTypeNone = getScore(rule.none, false);
var cumulativeImpacts = highestImpactForRuleTypeAny.concat(allUniqueImpactsForRuleTypeAll).concat(allUniqueImpactsForRuleTypeNone);
var cumulativeScores = getUniqueArr(cumulativeImpacts).sort(); //order lowest to highest

return cumulativeScores.reduce(function (out, cV) {
return out.length
? out + ', ' + capitalize(axeImpact[cV])
: capitalize(axeImpact[cV]);
}, '');
}


rules.map(function (rule) {

var impact = parseImpactForRule(rule);
rule.any = parseChecks(rule.any);
rule.all = parseChecks(rule.all);
rule.none = parseChecks(rule.none);

if (rule.metadata && !metadata.rules[rule.id]) {
// Translate rules
metadata.rules[rule.id] = parseMetaData(rule, 'rules');
metadata.rules[rule.id] = parseMetaData(rule, 'rules'); // Translate rules
}
descriptions.push([rule.id, entities.encode(rule.metadata.description), rule.tags.join(', '), rule.enabled === false ? false : true]);
descriptions.push([
rule.id,
entities.encode(rule.metadata.description),
impact,
rule.tags.join(', '),
rule.enabled === false ? false : true
]);
if (tags.length) {
rule.enabled = !!rule.tags.filter(function (t) {
return tags.indexOf(t) !== -1;
Expand Down
Loading