Add strings option to enable file-less scenarios.

This commit is contained in:
David Anson 2015-04-29 18:46:52 -07:00
parent fde1947031
commit 548e3d35cb
4 changed files with 176 additions and 87 deletions

View file

@ -53,86 +53,90 @@ function uniqueFilterForSorted(value, index, array) {
return (index === 0) || (value > array[index - 1]);
}
// Lints a single string
function lintContent(content, config) {
// Parse content into tokens and lines
var tokens = md.parse(content, {});
var lines = content.split(shared.newLineRe);
// Annotate tokens with line/lineNumber
tokens.forEach(function forToken(token) {
if (token.map) {
token.line = lines[token.map[0]];
token.lineNumber = token.map[0] + 1;
// Trim bottom of token to exclude whitespace lines
while (!(lines[token.map[1] - 1].trim())) {
token.map[1]--;
}
// Annotate children with lineNumber
var lineNumber = token.lineNumber;
(token.children || []).forEach(function forChild(child) {
child.lineNumber = lineNumber;
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
lineNumber++;
}
});
}
});
// Create parameters for rules
var params = {
"tokens": tokens,
"lines": lines
};
// Merge rules/tags and sanitize config
var mergedRules = {};
var ruleDefault = (config.default === undefined) || !!config.default;
rules.forEach(function forRule(rule) {
mergedRules[rule.name] = ruleDefault;
});
Object.keys(config).forEach(function forKey(key) {
var value = config[key];
if (value) {
if (!(value instanceof Object)) {
value = {};
}
} else {
value = false;
}
if (ruleToDescription[key]) {
mergedRules[key] = value;
} else if (tagToRules[key]) {
tagToRules[key].forEach(function forRule(rule) {
mergedRules[rule] = value;
});
}
});
// Run each enabled rule
var result = {};
rules.forEach(function forRule(rule) {
if (mergedRules[rule.name]) {
// Configure rule
params.options = mergedRules[rule.name];
var errors = [];
rule.func(params, errors);
// Record any errors
if (errors.length) {
errors.sort(numberComparison);
result[rule.name] = errors.filter(uniqueFilterForSorted);
}
}
});
return result;
}
// Lints a single file
function lintFile(file, config, synchronous, callback) {
// Callback for read file API
function readFile(err, contents) {
function lintContentWrapper(err, content) {
if (err) {
callback(err);
} else {
// Parse file into tokens and lines
var tokens = md.parse(contents, {});
var lines = contents.split(shared.newLineRe);
// Annotate tokens with line/lineNumber
tokens.forEach(function forToken(token) {
if (token.map) {
token.line = lines[token.map[0]];
token.lineNumber = token.map[0] + 1;
// Trim bottom of token to exclude whitespace lines
while (!(lines[token.map[1] - 1].trim())) {
token.map[1]--;
}
// Annotate children with lineNumber
var lineNumber = token.lineNumber;
(token.children || []).forEach(function forChild(child) {
child.lineNumber = lineNumber;
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
lineNumber++;
}
});
}
});
// Create parameters for rules
var params = {
"tokens": tokens,
"lines": lines
};
// Merge rules/tags and sanitize config
var mergedRules = {};
var ruleDefault = (config.default === undefined) || !!config.default;
rules.forEach(function forRule(rule) {
mergedRules[rule.name] = ruleDefault;
});
Object.keys(config).forEach(function forKey(key) {
var value = config[key];
if (value) {
if (!(value instanceof Object)) {
value = {};
}
} else {
value = false;
}
if (ruleToDescription[key]) {
mergedRules[key] = value;
} else if (tagToRules[key]) {
tagToRules[key].forEach(function forRule(rule) {
mergedRules[rule] = value;
});
}
});
// Run each enabled rule
var result = {};
rules.forEach(function forRule(rule) {
if (mergedRules[rule.name]) {
// Configure rule
params.options = mergedRules[rule.name];
var errors = [];
rule.func(params, errors);
// Record any errors
if (errors.length) {
errors.sort(numberComparison);
result[rule.name] = errors.filter(uniqueFilterForSorted);
}
}
});
callback(null, result);
return callback(err);
}
var result = lintContent(content, config);
callback(null, result);
}
// Make a/synchronous call to read file
if (synchronous) {
readFile(null, fs.readFileSync(file, shared.utf8Encoding));
lintContentWrapper(null, fs.readFileSync(file, shared.utf8Encoding));
} else {
fs.readFile(file, shared.utf8Encoding, readFile);
fs.readFile(file, shared.utf8Encoding, lintContentWrapper);
}
}
@ -156,27 +160,34 @@ function markdownlint(options, callback) {
options = options || {};
callback = callback || function noop() {};
var files = (options.files || []).slice();
var strings = options.strings || {};
var config = options.config || { "default": true };
var synchronous = (callback === markdownlintSynchronousCallback);
var results = new Results();
// Lint each input file
function lintFiles() {
// Helper to lint the next file in the array
function lintFilesArray() {
var file = files.shift();
if (file) {
lintFile(file, config, synchronous, function lintedFile(err, result) {
if (err) {
callback(err);
} else {
// Record errors and lint next file
results[file] = result;
lintFiles();
return callback(err);
}
// Record errors and lint next file
results[file] = result;
lintFilesArray();
});
} else {
callback(null, results);
}
}
lintFiles();
// Lint strings
Object.keys(strings).forEach(function forKey(key) {
var result = lintContent(strings[key] || "", config);
results[key] = result;
});
// Lint files
lintFilesArray();
// Return results
if (synchronous) {
return results;
}