Add options.resultVersion for more detailed error reporting (fixes #23).

This commit is contained in:
David Anson 2016-10-16 21:46:02 -07:00
parent 3a356467cd
commit 0ca8bc7bb6
11 changed files with 454 additions and 160 deletions

View file

@ -38,34 +38,51 @@ Results.prototype.toString = function resultsToString(useAlias) {
var results = [];
Object.keys(that).forEach(function forFile(file) {
var fileResults = that[file];
Object.keys(fileResults).forEach(function forRule(ruleName) {
var rule = ruleNameToRule[ruleName];
var ruleResults = fileResults[ruleName];
ruleResults.forEach(function forLine(lineNumber) {
var result =
if (Array.isArray(fileResults)) {
fileResults.forEach(function forResult(result) {
results.push(
file + ": " +
lineNumber + ": " +
(useAlias ? rule.aliases[0] : rule.name) + " " +
rule.desc;
results.push(result);
result.lineNumber + ": " +
result.ruleName + "/" +
result.ruleAlias + " " +
result.ruleDescription +
(result.errorDetail ?
" [" + result.errorDetail + "]" :
"") +
(result.errorContext ?
" [Context: \"" + result.errorContext + "\"]" :
""));
});
});
} else {
Object.keys(fileResults).forEach(function forRule(ruleName) {
var rule = ruleNameToRule[ruleName];
var ruleResults = fileResults[ruleName];
ruleResults.forEach(function forLine(lineNumber) {
var result =
file + ": " +
lineNumber + ": " +
(useAlias ? rule.aliases[0] : rule.name) + " " +
rule.desc;
results.push(result);
});
});
}
});
return results.join("\n");
};
// Array.sort comparison for number objects
function numberComparison(a, b) {
return a - b;
// Array.sort comparison for objects in errors array
function lineNumberComparison(a, b) {
return a.lineNumber - b.lineNumber;
}
// Function to return unique values from a sorted array
function uniqueFilterForSorted(value, index, array) {
return (index === 0) || (value > array[index - 1]);
// Function to return unique values from a sorted errors array
function uniqueFilterForSortedErrors(value, index, array) {
return (index === 0) || (value.lineNumber > array[index - 1].lineNumber);
}
// Lints a single string
function lintContent(content, config, frontMatter) { // eslint-disable-line
function lintContent(content, config, frontMatter, resultVersion) {
// Remove front matter (if present at beginning of content)
var frontMatterLines = 0;
if (frontMatter) {
@ -163,7 +180,7 @@ function lintContent(content, config, frontMatter) { // eslint-disable-line
}
});
}
var enabledRulesPerLineNumber = [ null ];
var enabledRulesPerLineNumber = new Array(1 + frontMatterLines);
lines.forEach(function forLine(line) {
var match = shared.inlineCommentRe.exec(line);
if (match) {
@ -182,25 +199,69 @@ function lintContent(content, config, frontMatter) { // eslint-disable-line
"lines": lines
};
// Run each rule
var result = {};
var result = (resultVersion === 1) ? [] : {};
rules.forEach(function forRule(rule) {
// Configure rule
params.options = mergedRules[rule.name];
var errors = [];
function addError(lineNumber, detail, context) {
errors.push({
"lineNumber": lineNumber + frontMatterLines,
"detail": detail || null,
"context": context || null
});
}
errors.add = function add(lineNumber) {
addError(lineNumber);
};
errors.addDetail = function addDetail(lineNumber, detail) {
addError(lineNumber, detail);
};
errors.addDetailIf = function addDetailIf(lineNumber, expected, actual) {
if (expected !== actual) {
addError(lineNumber, "Expected: " + expected + "; Actual: " + actual);
}
};
errors.addContext = function addContext(lineNumber, context, left, right) {
if (context.length <= 30) {
// Nothing to do
} else if (left && right) {
context = context.substr(0, 15) + "..." + context.substr(-15);
} else if (right) {
context = "..." + context.substr(-30);
} else {
context = context.substr(0, 30) + "...";
}
addError(lineNumber, null, context);
};
rule.func(params, errors);
// Record any errors (significant performance benefit from length check)
if (errors.length) {
errors.sort(numberComparison);
errors.sort(lineNumberComparison);
var filteredErrors = errors
.filter(uniqueFilterForSorted)
.filter(function removeDisabledRules(lineNumber) {
return enabledRulesPerLineNumber[lineNumber][rule.name];
.filter(uniqueFilterForSortedErrors)
.filter(function removeDisabledRules(error) {
return enabledRulesPerLineNumber[error.lineNumber][rule.name];
})
.map(function adjustLineNumbers(error) {
return error + frontMatterLines;
.map(function formatResults(error) {
if (resultVersion === 1) {
return {
"lineNumber": error.lineNumber,
"ruleName": rule.name,
"ruleAlias": rule.aliases[0],
"ruleDescription": rule.desc,
"errorDetail": error.detail,
"errorContext": error.context
};
}
return error.lineNumber;
});
if (filteredErrors.length) {
result[rule.name] = filteredErrors;
if (resultVersion === 1) {
result.push.apply(result, filteredErrors);
} else {
result[rule.name] = filteredErrors;
}
}
}
});
@ -208,12 +269,18 @@ function lintContent(content, config, frontMatter) { // eslint-disable-line
}
// Lints a single file
function lintFile(file, config, frontMatter, synchronous, callback) {
function lintFile(
file,
config,
frontMatter,
resultVersion,
synchronous,
callback) {
function lintContentWrapper(err, content) {
if (err) {
return callback(err);
}
var result = lintContent(content, config, frontMatter);
var result = lintContent(content, config, frontMatter, resultVersion);
callback(null, result);
}
// Make a/synchronous call to read file
@ -253,13 +320,14 @@ function markdownlint(options, callback) {
var frontMatter = (options.frontMatter === undefined) ?
shared.frontMatterRe : options.frontMatter;
var config = options.config || { "default": true };
var resultVersion = options.resultVersion || 0;
var synchronous = (callback === markdownlintSynchronousCallback);
var results = new Results();
// Helper to lint the next file in the array
function lintFilesArray() {
var file = files.shift();
if (file) {
lintFile(file, config, frontMatter, synchronous,
lintFile(file, config, frontMatter, resultVersion, synchronous,
function lintedFile(err, result) {
if (err) {
return callback(err);
@ -274,7 +342,11 @@ function markdownlint(options, callback) {
}
// Lint strings
Object.keys(strings).forEach(function forKey(key) {
var result = lintContent(strings[key] || "", config, frontMatter);
var result = lintContent(
strings[key] || "",
config,
frontMatter,
resultVersion);
results[key] = result;
});
// Lint files