Add validation of onError callback object for rules.

This commit is contained in:
David Anson 2018-02-27 21:14:02 -08:00
parent 802c81f929
commit 7a752784f1
7 changed files with 107 additions and 12 deletions

View file

@ -324,8 +324,36 @@ function lintContent(
var ruleNameFriendly = rule.names[0];
var ruleName = ruleNameFriendly.toUpperCase();
params.config = effectiveConfig[ruleName];
function throwError(property) {
throw new Error(
"Property '" + property + "' of onError parameter is incorrect.");
}
var errors = [];
function onError(errorInfo) {
if (!errorInfo ||
!errorInfo.lineNumber ||
!shared.isNumber(errorInfo.lineNumber)) {
throwError("lineNumber");
}
if ((errorInfo.detail !== null) &&
(errorInfo.detail !== undefined) &&
(!shared.isString(errorInfo.detail) ||
shared.isEmptyString(errorInfo.detail))) {
throwError("detail");
}
if ((errorInfo.context !== null) &&
(errorInfo.context !== undefined) &&
(!shared.isString(errorInfo.context) ||
shared.isEmptyString(errorInfo.context))) {
throwError("context");
}
if (errorInfo.range &&
(!Array.isArray(errorInfo.range) ||
(errorInfo.range.length !== 2) ||
!shared.isNumber(errorInfo.range[0]) ||
!shared.isNumber(errorInfo.range[1]))) {
throwError("range");
}
errors.push({
"lineNumber": errorInfo.lineNumber + frontMatterLines.length,
"detail": errorInfo.detail || null,

View file

@ -46,6 +46,11 @@ module.exports.clone = function clone(obj) {
return assign({}, obj);
};
// Returns true iff the input is a number
module.exports.isNumber = function isNumber(obj) {
return typeof obj === "number";
};
// Returns true iff the input is a string
module.exports.isString = function isString(obj) {
return typeof obj === "string";

View file

@ -2008,3 +2008,73 @@ function customRulesThrowForString(test) {
test.done();
});
};
module.exports.customRulesOnErrorNull = function customRulesOnErrorNull(test) {
test.expect(4);
var options = {
"customRules": [
{
"names": [ "name" ],
"description": "description",
"tags": [ "tag" ],
"function": function onErrorNull(params, onError) {
onError(null);
}
}
],
"strings": [ "String" ]
};
test.throws(function badErrorCall() {
markdownlint.sync(options);
}, function testError(err) {
test.ok(err, "Did not get an error for null object.");
test.ok(err instanceof Error, "Error not instance of Error.");
test.equal(err.message,
"Property 'lineNumber' of onError parameter is incorrect.",
"Incorrect message for bad object.");
return true;
}, "Did not get exception for null object.");
test.done();
};
module.exports.customRulesOnErrorBad = function customRulesOnErrorBad(test) {
test.expect(52);
[
[ "lineNumber", [ null, "string" ] ],
[ "detail", [ 10, "", [] ] ],
[ "context", [ 10, "", [] ] ],
[ "range", [ 10, [], [ 10 ], [ 10, null ], [ 10, 11, 12 ] ] ]
].forEach(function forProperty(property) {
var propertyName = property[0];
property[1].forEach(function forPropertyValue(propertyValue) {
var badObject = {
"lineNumber": 1
};
badObject[propertyName] = propertyValue;
var options = {
"customRules": [
{
"names": [ "name" ],
"description": "description",
"tags": [ "tag" ],
"function": function onErrorBad(params, onError) {
onError(badObject);
}
}
],
"strings": [ "String" ]
};
test.throws(function badErrorCall() {
markdownlint.sync(options);
}, function testError(err) {
test.ok(err, "Did not get an error for bad object.");
test.ok(err instanceof Error, "Error not instance of Error.");
test.equal(err.message,
"Property '" + propertyName + "' of onError parameter is incorrect.",
"Incorrect message for bad object.");
return true;
}, "Did not get exception for bad object.");
});
});
test.done();
};

View file

@ -14,8 +14,7 @@ module.exports = {
onError({
"lineNumber": blockquote.lineNumber,
"detail": "Blockquote spans " + lines + " line(s).",
"context": blockquote.line.substr(0, 7),
"range": null
"context": blockquote.line.substr(0, 7)
});
});
}

View file

@ -13,9 +13,7 @@ module.exports = {
if ((lineNumber % n) === 0) {
onError({
"lineNumber": lineNumber,
"detail": "Line number " + lineNumber,
"context": null,
"range": null
"detail": "Line number " + lineNumber
});
}
});

View file

@ -9,10 +9,7 @@ module.exports = {
"function": function rule(params, onError) {
// Unconditionally report an error for line 1
onError({
"lineNumber": 1,
"detail": null,
"context": null,
"range": null
"lineNumber": 1
});
}
};

View file

@ -17,9 +17,7 @@ module.exports = {
if (index !== -1) {
onError({
"lineNumber": text.lineNumber,
"detail": null,
"context": text.content.substr(index - 1, 4),
"range": null
"context": text.content.substr(index - 1, 4)
});
}
});