Remove params.tokenLists to simplify custom rule API.

This commit is contained in:
David Anson 2018-03-01 22:37:37 -08:00
parent 7a752784f1
commit b33acb81d9
2 changed files with 100 additions and 94 deletions

View file

@ -141,7 +141,6 @@ function removeFrontMatter(content, frontMatter) {
// Annotate tokens with line/lineNumber
function annotateTokens(tokens, lines) {
var tbodyMap = null;
var tokenLists = {};
tokens.forEach(function forToken(token) {
// Handle missing maps for table body
if (token.type === "tbody_open") {
@ -172,12 +171,7 @@ function annotateTokens(tokens, lines) {
}
});
}
if (!tokenLists[token.type]) {
tokenLists[token.type] = [];
}
tokenLists[token.type].push(token);
});
return tokenLists;
}
// Map rule names/tags to canonical rule name
@ -292,19 +286,16 @@ function lintContent(
ruleList, content, config, frontMatter, noInlineConfig, resultVersion,
callback) {
// Remove UTF-8 byte order marker (if present)
if (content.charCodeAt(0) === 0xfeff) {
content = content.slice(1);
}
content = content.replace(/^\ufeff/, "");
// Remove front matter
var removeFrontMatterResult = removeFrontMatter(content, frontMatter);
content = removeFrontMatterResult.content;
var frontMatterLines = removeFrontMatterResult.frontMatterLines;
// Ignore the content of HTML comments
content = shared.clearHtmlCommentText(content);
content = shared.clearHtmlCommentText(removeFrontMatterResult.content);
// Parse content into tokens and lines
var tokens = md.parse(content, {});
var lines = content.split(shared.newLineRe);
var tokenLists = annotateTokens(tokens, lines);
annotateTokens(tokens, lines);
var aliasToRuleNames = mapAliasToRuleNames(ruleList);
var effectiveConfig = getEffectiveConfig(ruleList, config, aliasToRuleNames);
var enabledRulesPerLineNumber = getEnabledRulesPerLineNumber(
@ -313,10 +304,10 @@ function lintContent(
// Create parameters for rules
var params = {
"tokens": tokens,
"tokenLists": tokenLists,
"lines": lines,
"frontMatterLines": frontMatterLines
};
shared.makeTokenCache(params);
// Function to run for each rule
var result = (resultVersion === 0) ? {} : [];
function forRule(rule) {
@ -402,8 +393,10 @@ function lintContent(
try {
ruleList.forEach(forRule);
} catch (ex) {
shared.makeTokenCache(null);
return callback(ex);
}
shared.makeTokenCache(null);
callback(null, result);
}

View file

@ -117,15 +117,23 @@ module.exports.headingStyleFor = function headingStyleFor(token) {
// Calls the provided function for each matching token
function filterTokens(params, type, callback) {
(params.tokenLists[type] || []).forEach(callback);
params.tokens.forEach(function forToken(token) {
if (token.type === type) {
callback(token);
}
});
}
module.exports.filterTokens = filterTokens;
var lastForEachLineParams = null;
var lastForEachLineResult = null;
// Calls the provided function for each line (with context)
module.exports.forEachLine = function forEachLine(params, callback) {
if (params !== lastForEachLineParams) {
var tokenCache = null;
// Caches line metadata and flattened lists for reuse
function makeTokenCache(params) {
if (!params) {
tokenCache = null;
return;
}
// Populate line metadata array
var lineMetadata = new Array(params.lines.length);
var fenceStart = null;
var inFence = false;
@ -156,12 +164,57 @@ module.exports.forEachLine = function forEachLine(params, callback) {
lineMetadata[i] += 8;
}
});
lastForEachLineParams = params;
lastForEachLineResult = lineMetadata;
// Flatten lists
var flattenedLists = [];
var stack = [];
var current = null;
var lastWithMap = { "map": [ 0, 1 ] };
params.tokens.forEach(function forToken(token) {
if ((token.type === "bullet_list_open") ||
(token.type === "ordered_list_open")) {
// Save current context and start a new one
stack.push(current);
current = {
"unordered": (token.type === "bullet_list_open"),
"parentsUnordered": !current ||
(current.unordered && current.parentsUnordered),
"open": token,
"items": [],
"nesting": stack.length - 1,
"lastLineIndex": -1,
"insert": flattenedLists.length
};
} else if ((token.type === "bullet_list_close") ||
(token.type === "ordered_list_close")) {
// Finalize current context and restore previous
current.lastLineIndex = lastWithMap.map[1];
flattenedLists.splice(current.insert, 0, current);
delete current.insert;
current = stack.pop();
} else if (token.type === "list_item_open") {
// Add list item
current.items.push(token);
} else if (token.map) {
// Track last token with map
lastWithMap = token;
}
});
// Cache results
tokenCache = {
"params": params,
"lineMetadata": lineMetadata,
"flattenedLists": flattenedLists
};
}
module.exports.makeTokenCache = makeTokenCache;
// Calls the provided function for each line (with context)
module.exports.forEachLine = function forEachLine(params, callback) {
// Invoke callback
params.lines.forEach(function forLine(line, lineIndex) {
var metadata = lastForEachLineResult[lineIndex];
tokenCache.params.lines.forEach(function forLine(line, lineIndex) {
var metadata = tokenCache.lineMetadata[lineIndex];
callback(
line,
lineIndex,
@ -197,49 +250,9 @@ module.exports.forEachHeading = function forEachHeading(params, callback) {
});
};
var lastFlattenListsParams = null;
var lastFlattenListsResult = null;
// Returns (nested) lists as a flat array (in order)
module.exports.flattenLists = function flattenLists(params) {
if (lastFlattenListsParams !== params) {
var lists = [];
var stack = [];
var current = null;
var lastWithMap = { "map": [ 0, 1 ] };
params.tokens.forEach(function forToken(token) {
if ((token.type === "bullet_list_open") ||
(token.type === "ordered_list_open")) {
// Save current context and start a new one
stack.push(current);
current = {
"unordered": (token.type === "bullet_list_open"),
"parentsUnordered": !current ||
(current.unordered && current.parentsUnordered),
"open": token,
"items": [],
"nesting": stack.length - 1,
"lastLineIndex": -1,
"insert": lists.length
};
} else if ((token.type === "bullet_list_close") ||
(token.type === "ordered_list_close")) {
// Finalize current context and restore previous
current.lastLineIndex = lastWithMap.map[1];
lists.splice(current.insert, 0, current);
delete current.insert;
current = stack.pop();
} else if (token.type === "list_item_open") {
// Add list item
current.items.push(token);
} else if (token.map) {
// Track last token with map
lastWithMap = token;
}
});
lastFlattenListsParams = params;
lastFlattenListsResult = lists;
}
return lastFlattenListsResult;
module.exports.flattenLists = function flattenLists() {
return tokenCache.flattenedLists;
};
// Adds a generic error object via the onError callback