Cache all top-level calls to filterByTypes (~7% runtime reduction).

This commit is contained in:
David Anson 2024-08-24 22:05:16 -07:00
parent 85e704f32a
commit dfcb4529f3
47 changed files with 427 additions and 481 deletions

File diff suppressed because it is too large Load diff

View file

@ -2,14 +2,69 @@
"use strict"; "use strict";
const helpers = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs");
/** @type {Map<string, object>} */
const map = new Map(); const map = new Map();
// eslint-disable-next-line no-undef-init
let params = undefined;
module.exports.set = (keyValuePairs) => { /**
for (const [ key, value ] of Object.entries(keyValuePairs)) { * Initializes (resets) the cache.
map.set(key, value); *
* @param {import("./markdownlint").RuleParams} [p] Rule parameters object.
* @returns {void}
*/
function initialize(p) {
map.clear();
params = p;
}
/**
* Gets a cached object value - computes it and caches it.
*
* @param {string} name Cache object name.
* @param {Function} getValue Getter for object value.
* @returns {Object} Object value.
*/
function getCached(name, getValue) {
if (map.has(name)) {
return map.get(name);
} }
}; const value = getValue();
module.exports.clear = () => map.clear(); map.set(name, value);
return value;
}
module.exports.referenceLinkImageData = /**
() => map.get("referenceLinkImageData"); * Filters a list of Micromark tokens by type and caches the result.
*
* @param {import("./markdownlint").MicromarkTokenType[]} types Types to allow.
* @param {boolean} [htmlFlow] Whether to include htmlFlow content.
* @returns {import("./markdownlint").MicromarkToken[]} Filtered tokens.
*/
function filterByTypesCached(types, htmlFlow) {
return getCached(
types.join("|"),
() => filterByTypes(params.parsers.micromark.tokens, types, htmlFlow)
);
}
/**
* Gets a reference link and image data object.
*
* @returns {Object} Reference link and image data object.
*/
function getReferenceLinkImageData() {
return getCached(
getReferenceLinkImageData.name,
() => helpers.getReferenceLinkImageData(params.parsers.micromark.tokens)
);
}
module.exports = {
initialize,
filterByTypesCached,
getReferenceLinkImageData
};

View file

@ -604,14 +604,13 @@ function lintContent(
const parsersNone = Object.freeze({}); const parsersNone = Object.freeze({});
const paramsBase = { const paramsBase = {
name, name,
"parsers": parsersMarkdownIt,
"lines": Object.freeze(lines), "lines": Object.freeze(lines),
"frontMatterLines": Object.freeze(frontMatterLines) "frontMatterLines": Object.freeze(frontMatterLines)
}; };
const referenceLinkImageData = cache.initialize({
helpers.getReferenceLinkImageData(micromarkTokens); ...paramsBase,
cache.set({ "parsers": parsersMicromark,
referenceLinkImageData "config": null
}); });
// Function to run for each rule // Function to run for each rule
let results = []; let results = [];
@ -826,7 +825,7 @@ function lintContent(
} catch (error) { } catch (error) {
callbackError(error); callbackError(error);
} finally { } finally {
cache.clear(); cache.initialize();
} }
} }

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes, getHeadingLevel } = require("../helpers/micromark.cjs"); const { getHeadingLevel } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -14,11 +15,7 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD001(params, onError) { "function": function MD001(params, onError) {
let prevLevel = Number.MAX_SAFE_INTEGER; let prevLevel = Number.MAX_SAFE_INTEGER;
const headings = filterByTypes( for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
params.parsers.micromark.tokens,
[ "atxHeading", "setextHeading" ]
);
for (const heading of headings) {
const level = getHeadingLevel(heading); const level = getHeadingLevel(heading);
if (level > prevLevel) { if (level > prevLevel) {
addErrorDetailIf( addErrorDetailIf(

View file

@ -3,8 +3,8 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes, getHeadingLevel, getHeadingStyle } = const { getHeadingLevel, getHeadingStyle } = require("../helpers/micromark.cjs");
require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -15,11 +15,7 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD003(params, onError) { "function": function MD003(params, onError) {
let style = String(params.config.style || "consistent"); let style = String(params.config.style || "consistent");
const headings = filterByTypes( for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
params.parsers.micromark.tokens,
[ "atxHeading", "setextHeading" ]
);
for (const heading of headings) {
const styleForToken = getHeadingStyle(heading); const styleForToken = getHeadingStyle(heading);
if (style === "consistent") { if (style === "consistent") {
style = styleForToken; style = styleForToken;

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes, getDescendantsByType, getTokenParentOfType } = require("../helpers/micromark.cjs"); const { getDescendantsByType, getTokenParentOfType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const markerToStyle = { const markerToStyle = {
"-": "dash", "-": "dash",
@ -39,11 +40,12 @@ module.exports = {
const style = String(params.config.style || "consistent"); const style = String(params.config.style || "consistent");
let expectedStyle = validStyles.has(style) ? style : "dash"; let expectedStyle = validStyles.has(style) ? style : "dash";
const nestingStyles = []; const nestingStyles = [];
for (const listUnordered of filterByTypes(params.parsers.micromark.tokens, [ "listUnordered" ])) { for (const listUnordered of filterByTypesCached([ "listUnordered" ])) {
let nesting = 0; let nesting = 0;
if (style === "sublist") { if (style === "sublist") {
/** @type {import("../helpers/micromark.cjs").Token | null} */ /** @type {import("../helpers/micromark.cjs").Token | null} */
let parent = listUnordered; let parent = listUnordered;
// @ts-ignore
while ((parent = getTokenParentOfType(parent, [ "listOrdered", "listUnordered" ]))) { while ((parent = getTokenParentOfType(parent, [ "listOrdered", "listUnordered" ]))) {
nesting++; nesting++;
} }

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addError, addErrorDetailIf } = require("../helpers"); const { addError, addErrorDetailIf } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -13,11 +13,7 @@ module.exports = {
"tags": [ "bullet", "ul", "indentation" ], "tags": [ "bullet", "ul", "indentation" ],
"parser": "micromark", "parser": "micromark",
"function": function MD005(params, onError) { "function": function MD005(params, onError) {
const lists = filterByTypes( for (const list of filterByTypesCached([ "listOrdered", "listUnordered" ])) {
params.parsers.micromark.tokens,
[ "listOrdered", "listUnordered" ]
);
for (const list of lists) {
const expectedIndent = list.startColumn - 1; const expectedIndent = list.startColumn - 1;
let expectedEnd = 0; let expectedEnd = 0;
let endMatching = false; let endMatching = false;

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes, getTokenParentOfType } = require("../helpers/micromark.cjs"); const { getTokenParentOfType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("markdownlint-micromark").TokenType[] */ /** @type import("markdownlint-micromark").TokenType[] */
@ -27,10 +28,7 @@ module.exports = {
const startIndent = Number(params.config.start_indent || indent); const startIndent = Number(params.config.start_indent || indent);
const unorderedListNesting = new Map(); const unorderedListNesting = new Map();
let lastBlockQuotePrefix = null; let lastBlockQuotePrefix = null;
const tokens = filterByTypes( const tokens = filterByTypesCached(unorderedListTypes);
params.parsers.micromark.tokens,
unorderedListTypes
);
for (const token of tokens) { for (const token of tokens) {
const { endColumn, parent, startColumn, startLine, type } = token; const { endColumn, parent, startColumn, startLine, type } = token;
if (type === "blockQuotePrefix") { if (type === "blockQuotePrefix") {
@ -40,6 +38,7 @@ module.exports = {
/** @type {import("../helpers/micromark.cjs").Token | null} */ /** @type {import("../helpers/micromark.cjs").Token | null} */
let current = token; let current = token;
while ( while (
// @ts-ignore
(current = getTokenParentOfType(current, unorderedParentTypes)) (current = getTokenParentOfType(current, unorderedParentTypes))
) { ) {
if (current.type === "listUnordered") { if (current.type === "listUnordered") {

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addError } = require("../helpers"); const { addError } = require("../helpers");
const { addRangeToSet, filterByTypes } = require("../helpers/micromark.cjs"); const { addRangeToSet } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -17,17 +18,16 @@ module.exports = {
brSpaces = Number((brSpaces === undefined) ? 2 : brSpaces); brSpaces = Number((brSpaces === undefined) ? 2 : brSpaces);
const listItemEmptyLines = !!params.config.list_item_empty_lines; const listItemEmptyLines = !!params.config.list_item_empty_lines;
const strict = !!params.config.strict; const strict = !!params.config.strict;
const { tokens } = params.parsers.micromark;
const codeBlockLineNumbers = new Set(); const codeBlockLineNumbers = new Set();
for (const codeBlock of filterByTypes(tokens, [ "codeFenced" ])) { for (const codeBlock of filterByTypesCached([ "codeFenced" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine + 1, codeBlock.endLine - 1); addRangeToSet(codeBlockLineNumbers, codeBlock.startLine + 1, codeBlock.endLine - 1);
} }
for (const codeBlock of filterByTypes(tokens, [ "codeIndented" ])) { for (const codeBlock of filterByTypesCached([ "codeIndented" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine); addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
} }
const listItemLineNumbers = new Set(); const listItemLineNumbers = new Set();
if (listItemEmptyLines) { if (listItemEmptyLines) {
for (const listBlock of filterByTypes(tokens, [ "listOrdered", "listUnordered" ])) { for (const listBlock of filterByTypesCached([ "listOrdered", "listUnordered" ])) {
addRangeToSet(listItemLineNumbers, listBlock.startLine, listBlock.endLine); addRangeToSet(listItemLineNumbers, listBlock.startLine, listBlock.endLine);
let trailingIndent = true; let trailingIndent = true;
for (let i = listBlock.children.length - 1; i >= 0; i--) { for (let i = listBlock.children.length - 1; i >= 0; i--) {
@ -53,10 +53,10 @@ module.exports = {
const paragraphLineNumbers = new Set(); const paragraphLineNumbers = new Set();
const codeInlineLineNumbers = new Set(); const codeInlineLineNumbers = new Set();
if (strict) { if (strict) {
for (const paragraph of filterByTypes(tokens, [ "paragraph" ])) { for (const paragraph of filterByTypesCached([ "paragraph" ])) {
addRangeToSet(paragraphLineNumbers, paragraph.startLine, paragraph.endLine - 1); addRangeToSet(paragraphLineNumbers, paragraph.startLine, paragraph.endLine - 1);
} }
for (const codeText of filterByTypes(tokens, [ "codeText" ])) { for (const codeText of filterByTypesCached([ "codeText" ])) {
addRangeToSet(codeInlineLineNumbers, codeText.startLine, codeText.endLine - 1); addRangeToSet(codeInlineLineNumbers, codeText.startLine, codeText.endLine - 1);
} }
} }

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addError, withinAnyRange } = require("../helpers"); const { addError, withinAnyRange } = require("../helpers");
const { filterByTypes, getDescendantsByType, getExclusionsForToken } = require("../helpers/micromark.cjs"); const { getDescendantsByType, getExclusionsForToken } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const tabRe = /\t+/g; const tabRe = /\t+/g;
@ -36,10 +37,7 @@ module.exports = {
} else { } else {
exclusionTypes.push("codeFenced", "codeIndented", "codeText"); exclusionTypes.push("codeFenced", "codeIndented", "codeText");
} }
const codeTokens = filterByTypes( const codeTokens = filterByTypesCached(exclusionTypes).filter((token) => {
params.parsers.micromark.tokens,
exclusionTypes
).filter((token) => {
if ((token.type === "codeFenced") && (ignoreCodeLanguages.size > 0)) { if ((token.type === "codeFenced") && (ignoreCodeLanguages.size > 0)) {
const fenceInfos = getDescendantsByType(token, [ "codeFencedFence", "codeFencedFenceInfo" ]); const fenceInfos = getDescendantsByType(token, [ "codeFencedFence", "codeFencedFenceInfo" ]);
return fenceInfos.every((fenceInfo) => ignoreCodeLanguages.has(fenceInfo.text.toLowerCase())); return fenceInfos.every((fenceInfo) => ignoreCodeLanguages.has(fenceInfo.text.toLowerCase()));

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addError, withinAnyRange } = require("../helpers"); const { addError, withinAnyRange } = require("../helpers");
const { addRangeToSet, getExclusionsForToken, filterByTypes } = require("../helpers/micromark.cjs"); const { addRangeToSet, getExclusionsForToken } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const reversedLinkRe = const reversedLinkRe =
/(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)\](?!\()/g; /(^|[^\\])\(([^()]+)\)\[([^\]^][^\]]*)\](?!\()/g;
@ -16,13 +17,12 @@ module.exports = {
"tags": [ "links" ], "tags": [ "links" ],
"parser": "micromark", "parser": "micromark",
"function": function MD011(params, onError) { "function": function MD011(params, onError) {
const { tokens } = params.parsers.micromark;
const codeBlockLineNumbers = new Set(); const codeBlockLineNumbers = new Set();
for (const codeBlock of filterByTypes(tokens, [ "codeFenced", "codeIndented" ])) { for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine); addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
} }
const exclusions = []; const exclusions = [];
for (const codeText of filterByTypes(tokens, [ "codeText" ])) { for (const codeText of filterByTypesCached([ "codeText" ])) {
exclusions.push(...getExclusionsForToken(params.lines, codeText)); exclusions.push(...getExclusionsForToken(params.lines, codeText));
} }
for (const [ lineIndex, line ] of params.lines.entries()) { for (const [ lineIndex, line ] of params.lines.entries()) {

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { addRangeToSet, filterByTypes } = require("../helpers/micromark.cjs"); const { addRangeToSet } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -14,9 +15,9 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD012(params, onError) { "function": function MD012(params, onError) {
const maximum = Number(params.config.maximum || 1); const maximum = Number(params.config.maximum || 1);
const { lines, parsers } = params; const { lines } = params;
const codeBlockLineNumbers = new Set(); const codeBlockLineNumbers = new Set();
for (const codeBlock of filterByTypes(parsers.micromark.tokens, [ "codeFenced", "codeIndented" ])) { for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine); addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
} }
let count = 0; let count = 0;

View file

@ -3,8 +3,9 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { referenceLinkImageData } = require("./cache"); const { getReferenceLinkImageData } = require("./cache");
const { addRangeToSet, filterByTypes, getDescendantsByType } = require("../helpers/micromark.cjs"); const { addRangeToSet, getDescendantsByType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const longLineRePrefix = "^.{"; const longLineRePrefix = "^.{";
const longLineRePostfixRelaxed = "}.*\\s.*$"; const longLineRePostfixRelaxed = "}.*\\s.*$";
@ -40,25 +41,24 @@ module.exports = {
const includeTables = (tables === undefined) ? true : !!tables; const includeTables = (tables === undefined) ? true : !!tables;
const headings = params.config.headings; const headings = params.config.headings;
const includeHeadings = (headings === undefined) ? true : !!headings; const includeHeadings = (headings === undefined) ? true : !!headings;
const { tokens } = params.parsers.micromark;
const headingLineNumbers = new Set(); const headingLineNumbers = new Set();
for (const heading of filterByTypes(tokens, [ "atxHeading", "setextHeading" ])) { for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
addRangeToSet(headingLineNumbers, heading.startLine, heading.endLine); addRangeToSet(headingLineNumbers, heading.startLine, heading.endLine);
} }
const codeBlockLineNumbers = new Set(); const codeBlockLineNumbers = new Set();
for (const codeBlock of filterByTypes(tokens, [ "codeFenced", "codeIndented" ])) { for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine); addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
} }
const tableLineNumbers = new Set(); const tableLineNumbers = new Set();
for (const table of filterByTypes(tokens, [ "table" ])) { for (const table of filterByTypesCached([ "table" ])) {
addRangeToSet(tableLineNumbers, table.startLine, table.endLine); addRangeToSet(tableLineNumbers, table.startLine, table.endLine);
} }
const linkLineNumbers = new Set(); const linkLineNumbers = new Set();
for (const link of filterByTypes(tokens, [ "autolink", "image", "link", "literalAutolink" ])) { for (const link of filterByTypesCached([ "autolink", "image", "link", "literalAutolink" ])) {
addRangeToSet(linkLineNumbers, link.startLine, link.endLine); addRangeToSet(linkLineNumbers, link.startLine, link.endLine);
} }
const paragraphDataLineNumbers = new Set(); const paragraphDataLineNumbers = new Set();
for (const paragraph of filterByTypes(tokens, [ "paragraph" ])) { for (const paragraph of filterByTypesCached([ "paragraph" ])) {
for (const data of getDescendantsByType(paragraph, [ "data" ])) { for (const data of getDescendantsByType(paragraph, [ "data" ])) {
addRangeToSet(paragraphDataLineNumbers, data.startLine, data.endLine); addRangeToSet(paragraphDataLineNumbers, data.startLine, data.endLine);
} }
@ -69,7 +69,7 @@ module.exports = {
linkOnlyLineNumbers.add(lineNumber); linkOnlyLineNumbers.add(lineNumber);
} }
} }
const definitionLineIndices = new Set(referenceLinkImageData().definitionLineIndices); const definitionLineIndices = new Set(getReferenceLinkImageData().definitionLineIndices);
for (let lineIndex = 0; lineIndex < params.lines.length; lineIndex++) { for (let lineIndex = 0; lineIndex < params.lines.length; lineIndex++) {
const line = params.lines[lineIndex]; const line = params.lines[lineIndex];
const lineNumber = lineIndex + 1; const lineNumber = lineIndex + 1;

View file

@ -4,6 +4,7 @@
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypes } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const dollarCommandRe = /^(\s*)(\$\s+)/; const dollarCommandRe = /^(\s*)(\$\s+)/;
@ -15,11 +16,7 @@ module.exports = {
"tags": [ "code" ], "tags": [ "code" ],
"parser": "micromark", "parser": "micromark",
"function": function MD014(params, onError) { "function": function MD014(params, onError) {
const codeBlocks = filterByTypes( for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
params.parsers.micromark.tokens,
[ "codeFenced", "codeIndented" ]
);
for (const codeBlock of codeBlocks) {
const codeFlowValues = filterByTypes( const codeFlowValues = filterByTypes(
codeBlock.children, codeBlock.children,
[ "codeFlowValue" ] [ "codeFlowValue" ]

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { addRangeToSet, filterByTypes } = require("../helpers/micromark.cjs"); const { addRangeToSet } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -13,9 +14,9 @@ module.exports = {
"tags": [ "headings", "atx", "spaces" ], "tags": [ "headings", "atx", "spaces" ],
"parser": "micromark", "parser": "micromark",
"function": function MD018(params, onError) { "function": function MD018(params, onError) {
const { lines, parsers } = params; const { lines } = params;
const ignoreBlockLineNumbers = new Set(); const ignoreBlockLineNumbers = new Set();
for (const ignoreBlock of filterByTypes(parsers.micromark.tokens, [ "codeIndented", "codeFenced", "htmlFlow" ])) { for (const ignoreBlock of filterByTypesCached([ "codeFenced", "codeIndented", "htmlFlow" ])) {
addRangeToSet(ignoreBlockLineNumbers, ignoreBlock.startLine, ignoreBlock.endLine); addRangeToSet(ignoreBlockLineNumbers, ignoreBlock.startLine, ignoreBlock.endLine);
} }
for (const [ lineIndex, line ] of lines.entries()) { for (const [ lineIndex, line ] of lines.entries()) {

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers/helpers"); const { addErrorContext } = require("../helpers/helpers");
const { filterByTypes, getHeadingStyle } = require("../helpers/micromark.cjs"); const { getHeadingStyle } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
/** /**
* Validate heading sequence and whitespace length at start or end. * Validate heading sequence and whitespace length at start or end.
@ -55,10 +56,8 @@ module.exports = [
"tags": [ "headings", "atx", "spaces" ], "tags": [ "headings", "atx", "spaces" ],
"parser": "micromark", "parser": "micromark",
"function": function MD019(params, onError) { "function": function MD019(params, onError) {
const atxHeadings = filterByTypes( const atxHeadings = filterByTypesCached([ "atxHeading" ])
params.parsers.micromark.tokens, .filter((heading) => getHeadingStyle(heading) === "atx");
[ "atxHeading" ]
).filter((heading) => getHeadingStyle(heading) === "atx");
for (const atxHeading of atxHeadings) { for (const atxHeading of atxHeadings) {
validateHeadingSpaces(onError, atxHeading, 1); validateHeadingSpaces(onError, atxHeading, 1);
} }
@ -70,10 +69,8 @@ module.exports = [
"tags": [ "headings", "atx_closed", "spaces" ], "tags": [ "headings", "atx_closed", "spaces" ],
"parser": "micromark", "parser": "micromark",
"function": function MD021(params, onError) { "function": function MD021(params, onError) {
const atxClosedHeadings = filterByTypes( const atxClosedHeadings = filterByTypesCached([ "atxHeading" ])
params.parsers.micromark.tokens, .filter((heading) => getHeadingStyle(heading) === "atx_closed");
[ "atxHeading" ]
).filter((heading) => getHeadingStyle(heading) === "atx_closed");
for (const atxClosedHeading of atxClosedHeadings) { for (const atxClosedHeading of atxClosedHeadings) {
validateHeadingSpaces(onError, atxClosedHeading, 1); validateHeadingSpaces(onError, atxClosedHeading, 1);
validateHeadingSpaces(onError, atxClosedHeading, -1); validateHeadingSpaces(onError, atxClosedHeading, -1);

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { addRangeToSet, filterByTypes } = require("../helpers/micromark.cjs"); const { addRangeToSet } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -13,9 +14,9 @@ module.exports = {
"tags": [ "headings", "atx_closed", "spaces" ], "tags": [ "headings", "atx_closed", "spaces" ],
"parser": "micromark", "parser": "micromark",
"function": function MD020(params, onError) { "function": function MD020(params, onError) {
const { lines, parsers } = params; const { lines } = params;
const ignoreBlockLineNumbers = new Set(); const ignoreBlockLineNumbers = new Set();
for (const ignoreBlock of filterByTypes(parsers.micromark.tokens, [ "codeIndented", "codeFenced", "htmlFlow" ])) { for (const ignoreBlock of filterByTypesCached([ "codeFenced", "codeIndented", "htmlFlow" ])) {
addRangeToSet(ignoreBlockLineNumbers, ignoreBlock.startLine, ignoreBlock.endLine); addRangeToSet(ignoreBlockLineNumbers, ignoreBlock.startLine, ignoreBlock.endLine);
} }
for (const [ lineIndex, line ] of lines.entries()) { for (const [ lineIndex, line ] of lines.entries()) {

View file

@ -2,9 +2,9 @@
"use strict"; "use strict";
const { addErrorDetailIf, blockquotePrefixRe, isBlankLine } = const { addErrorDetailIf, blockquotePrefixRe, isBlankLine } = require("../helpers");
require("../helpers"); const { getHeadingLevel } = require("../helpers/micromark.cjs");
const { filterByTypes, getHeadingLevel } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
const defaultLines = 1; const defaultLines = 1;
@ -41,12 +41,7 @@ module.exports = {
const getLinesAbove = getLinesFunction(params.config.lines_above); const getLinesAbove = getLinesFunction(params.config.lines_above);
const getLinesBelow = getLinesFunction(params.config.lines_below); const getLinesBelow = getLinesFunction(params.config.lines_below);
const { lines } = params; const { lines } = params;
const headings = filterByTypes( for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
// eslint-disable-next-line unicorn/consistent-destructuring
params.parsers.micromark.tokens,
[ "atxHeading", "setextHeading" ]
);
for (const heading of headings) {
const { startLine, endLine } = heading; const { startLine, endLine } = heading;
const line = lines[startLine - 1].trim(); const line = lines[startLine - 1].trim();

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -13,10 +13,7 @@ module.exports = {
"tags": [ "headings", "spaces" ], "tags": [ "headings", "spaces" ],
"parser": "micromark", "parser": "micromark",
"function": function MD023(params, onError) { "function": function MD023(params, onError) {
const headings = filterByTypes( const headings = filterByTypesCached([ "atxHeading", "linePrefix", "setextHeading" ]);
params.parsers.micromark.tokens,
[ "atxHeading", "linePrefix", "setextHeading" ]
);
for (let i = 0; i < headings.length - 1; i++) { for (let i = 0; i < headings.length - 1; i++) {
if ( if (
(headings[i].type === "linePrefix") && (headings[i].type === "linePrefix") &&

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByTypes, getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs"); const { getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -17,11 +18,7 @@ module.exports = {
const knownContents = [ null, [] ]; const knownContents = [ null, [] ];
let lastLevel = 1; let lastLevel = 1;
let knownContent = knownContents[lastLevel]; let knownContent = knownContents[lastLevel];
const headings = filterByTypes( for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
params.parsers.micromark.tokens,
[ "atxHeading", "setextHeading" ]
);
for (const heading of headings) {
const headingText = getHeadingText(heading); const headingText = getHeadingText(heading);
if (siblingsOnly) { if (siblingsOnly) {
const newLevel = getHeadingLevel(heading); const newLevel = getHeadingLevel(heading);

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext, frontMatterHasTitle } = require("../helpers"); const { addErrorContext, frontMatterHasTitle } = require("../helpers");
const { filterByTypes, getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs"); const { getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -20,11 +21,7 @@ module.exports = {
params.config.front_matter_title params.config.front_matter_title
); );
let hasTopLevelHeading = false; let hasTopLevelHeading = false;
const headings = filterByTypes( for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
params.parsers.micromark.tokens,
[ "atxHeading", "setextHeading" ]
);
for (const heading of headings) {
const headingLevel = getHeadingLevel(heading); const headingLevel = getHeadingLevel(heading);
if (headingLevel === level) { if (headingLevel === level) {
if (hasTopLevelHeading || foundFrontMatterTitle) { if (hasTopLevelHeading || foundFrontMatterTitle) {

View file

@ -4,7 +4,7 @@
const { addError, allPunctuationNoQuestion, endOfLineGemojiCodeRe, const { addError, allPunctuationNoQuestion, endOfLineGemojiCodeRe,
endOfLineHtmlEntityRe, escapeForRegExp } = require("../helpers"); endOfLineHtmlEntityRe, escapeForRegExp } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -20,10 +20,7 @@ module.exports = {
); );
const trailingPunctuationRe = const trailingPunctuationRe =
new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$"); new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$");
const headings = filterByTypes( const headings = filterByTypesCached([ "atxHeadingText", "setextHeadingText" ]);
params.parsers.micromark.tokens,
[ "atxHeadingText", "setextHeadingText" ]
);
for (const heading of headings) { for (const heading of headings) {
const { endColumn, endLine, text } = heading; const { endColumn, endLine, text } = heading;
const match = trailingPunctuationRe.exec(text); const match = trailingPunctuationRe.exec(text);

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -13,9 +13,8 @@ module.exports = {
"tags": ["blockquote", "whitespace", "indentation"], "tags": ["blockquote", "whitespace", "indentation"],
"parser": "micromark", "parser": "micromark",
"function": function MD027(params, onError) { "function": function MD027(params, onError) {
const micromarkTokens = params.parsers.micromark.tokens; for (const token of filterByTypesCached([ "linePrefix" ])) {
for (const token of filterByTypes(micromarkTokens, [ "linePrefix" ])) { const siblings = token.parent?.children || params.parsers.micromark.tokens;
const siblings = token.parent?.children || micromarkTokens;
if (siblings[siblings.indexOf(token) - 1]?.type === "blockQuotePrefix") { if (siblings[siblings.indexOf(token) - 1]?.type === "blockQuotePrefix") {
const { startColumn, startLine, text } = token; const { startColumn, startLine, text } = token;
const { length } = text; const { length } = text;

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addError } = require("../helpers"); const { addError } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
const ignoreTypes = new Set([ "lineEnding", "listItemIndent", "linePrefix" ]); const ignoreTypes = new Set([ "lineEnding", "listItemIndent", "linePrefix" ]);
@ -15,10 +15,9 @@ module.exports = {
"tags": [ "blockquote", "whitespace" ], "tags": [ "blockquote", "whitespace" ],
"parser": "micromark", "parser": "micromark",
"function": function MD028(params, onError) { "function": function MD028(params, onError) {
const micromarkTokens = params.parsers.micromark.tokens; for (const token of filterByTypesCached([ "blockQuote" ])) {
for (const token of filterByTypes(micromarkTokens, [ "blockQuote" ])) {
const errorLineNumbers = []; const errorLineNumbers = [];
const siblings = token.parent?.children || micromarkTokens; const siblings = token.parent?.children || params.parsers.micromark.tokens;
for (let i = siblings.indexOf(token) + 1; i < siblings.length; i++) { for (let i = siblings.indexOf(token) + 1; i < siblings.length; i++) {
const sibling = siblings[i]; const sibling = siblings[i];
const { startLine, type } = sibling; const { startLine, type } = sibling;

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes, getDescendantsByType, getTokenTextByType } = require("../helpers/micromark.cjs"); const { getDescendantsByType, getTokenTextByType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const listStyleExamples = { const listStyleExamples = {
"one": "1/1/1", "one": "1/1/1",
@ -30,7 +31,7 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD029(params, onError) { "function": function MD029(params, onError) {
const style = String(params.config.style || "one_or_ordered"); const style = String(params.config.style || "one_or_ordered");
for (const listOrdered of filterByTypes(params.parsers.micromark.tokens, [ "listOrdered" ])) { for (const listOrdered of filterByTypesCached([ "listOrdered" ])) {
const listItemPrefixes = getDescendantsByType(listOrdered, [ "listItemPrefix" ]); const listItemPrefixes = getDescendantsByType(listOrdered, [ "listItemPrefix" ]);
let expected = 1; let expected = 1;
let incrementing = false; let incrementing = false;

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -17,11 +17,7 @@ module.exports = {
const olSingle = Number(params.config.ol_single || 1); const olSingle = Number(params.config.ol_single || 1);
const ulMulti = Number(params.config.ul_multi || 1); const ulMulti = Number(params.config.ul_multi || 1);
const olMulti = Number(params.config.ol_multi || 1); const olMulti = Number(params.config.ol_multi || 1);
const lists = filterByTypes( for (const list of filterByTypesCached([ "listOrdered", "listUnordered" ])) {
params.parsers.micromark.tokens,
[ "listOrdered", "listUnordered" ]
);
for (const list of lists) {
const ordered = (list.type === "listOrdered"); const ordered = (list.type === "listOrdered");
const listItemPrefixes = const listItemPrefixes =
list.children.filter((token) => (token.type === "listItemPrefix")); list.children.filter((token) => (token.type === "listItemPrefix"));

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext, isBlankLine } = require("../helpers"); const { addErrorContext, isBlankLine } = require("../helpers");
const { filterByTypes, getTokenParentOfType } = require("../helpers/micromark.cjs"); const { getTokenParentOfType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const codeFencePrefixRe = /^(.*?)[`~]/; const codeFencePrefixRe = /^(.*?)[`~]/;
@ -47,8 +48,8 @@ module.exports = {
"function": function MD031(params, onError) { "function": function MD031(params, onError) {
const listItems = params.config.list_items; const listItems = params.config.list_items;
const includeListItems = (listItems === undefined) ? true : !!listItems; const includeListItems = (listItems === undefined) ? true : !!listItems;
const { lines, parsers } = params; const { lines } = params;
for (const codeBlock of filterByTypes(parsers.micromark.tokens, [ "codeFenced" ])) { for (const codeBlock of filterByTypesCached([ "codeFenced" ])) {
if (includeListItems || !(getTokenParentOfType(codeBlock, [ "listOrdered", "listUnordered" ]))) { if (includeListItems || !(getTokenParentOfType(codeBlock, [ "listOrdered", "listUnordered" ]))) {
if (!isBlankLine(lines[codeBlock.startLine - 2])) { if (!isBlankLine(lines[codeBlock.startLine - 2])) {
addError(onError, lines, codeBlock.startLine, true); addError(onError, lines, codeBlock.startLine, true);

View file

@ -3,8 +3,8 @@
"use strict"; "use strict";
const { addError, nextLinesRe } = require("../helpers"); const { addError, nextLinesRe } = require("../helpers");
const { filterByTypes, getHtmlTagInfo } = const { getHtmlTagInfo } = require("../helpers/micromark.cjs");
require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -17,7 +17,7 @@ module.exports = {
let allowedElements = params.config.allowed_elements; let allowedElements = params.config.allowed_elements;
allowedElements = Array.isArray(allowedElements) ? allowedElements : []; allowedElements = Array.isArray(allowedElements) ? allowedElements : [];
allowedElements = allowedElements.map((element) => element.toLowerCase()); allowedElements = allowedElements.map((element) => element.toLowerCase());
for (const token of filterByTypes(params.parsers.micromark.tokens, [ "htmlText" ], true)) { for (const token of filterByTypesCached([ "htmlText" ], true)) {
const htmlTagInfo = getHtmlTagInfo(token); const htmlTagInfo = getHtmlTagInfo(token);
if ( if (
htmlTagInfo && htmlTagInfo &&

View file

@ -3,8 +3,8 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByPredicate, filterByTypes, getHtmlTagInfo, inHtmlFlow, parse } = const { filterByPredicate, getHtmlTagInfo, inHtmlFlow, parse } = require("../helpers/micromark.cjs");
require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -70,10 +70,7 @@ module.exports = {
} }
) )
); );
const autoLinks = filterByTypes( const autoLinks = filterByTypesCached([ "literalAutolink" ]);
params.parsers.micromark.tokens,
[ "literalAutolink" ]
);
if (autoLinks.length > 0) { if (autoLinks.length > 0) {
// Re-parse with correct link/image reference definition handling // Re-parse with correct link/image reference definition handling
const document = params.lines.join("\n"); const document = params.lines.join("\n");

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -14,10 +14,7 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD035(params, onError) { "function": function MD035(params, onError) {
let style = String(params.config.style || "consistent").trim(); let style = String(params.config.style || "consistent").trim();
const thematicBreaks = filterByTypes( const thematicBreaks = filterByTypesCached([ "thematicBreak" ]);
params.parsers.micromark.tokens,
[ "thematicBreak" ]
);
for (const token of thematicBreaks) { for (const token of thematicBreaks) {
const { startLine, text } = token; const { startLine, text } = token;
if (style === "consistent") { if (style === "consistent") {

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext, allPunctuation } = require("../helpers"); const { addErrorContext, allPunctuation } = require("../helpers");
const { filterByTypes, matchAndGetTokensByType } = require("../helpers/micromark.cjs"); const { matchAndGetTokensByType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
/** @typedef {import("../helpers/micromark.cjs").TokenType} TokenType */ /** @typedef {import("../helpers/micromark.cjs").TokenType} TokenType */
/** @type {Map<TokenType, TokenType[]>} */ /** @type {Map<TokenType, TokenType[]>} */
@ -24,7 +25,7 @@ module.exports = {
punctuation = String((punctuation === undefined) ? allPunctuation : punctuation); punctuation = String((punctuation === undefined) ? allPunctuation : punctuation);
const punctuationRe = new RegExp("[" + punctuation + "]$"); const punctuationRe = new RegExp("[" + punctuation + "]$");
const paragraphTokens = const paragraphTokens =
filterByTypes(params.parsers.micromark.tokens, [ "paragraph" ]). filterByTypesCached([ "paragraph" ]).
filter((token) => filter((token) =>
(token.parent?.type === "content") && !token.parent?.parent && (token.children.length === 1) (token.parent?.type === "content") && !token.parent?.parent && (token.children.length === 1)
); );

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByTypes, tokenIfType } = require("../helpers/micromark.cjs"); const { tokenIfType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const leftSpaceRe = /^\s(?:[^`]|$)/; const leftSpaceRe = /^\s(?:[^`]|$)/;
const rightSpaceRe = /[^`]\s$/; const rightSpaceRe = /[^`]\s$/;
@ -26,10 +27,7 @@ module.exports = {
"tags": [ "whitespace", "code" ], "tags": [ "whitespace", "code" ],
"parser": "micromark", "parser": "micromark",
"function": function MD038(params, onError) { "function": function MD038(params, onError) {
const codeTexts = filterByTypes( const codeTexts = filterByTypesCached([ "codeText" ]);
params.parsers.micromark.tokens,
[ "codeText" ]
);
for (const codeText of codeTexts) { for (const codeText of codeTexts) {
const { children } = codeText; const { children } = codeText;
const first = 0; const first = 0;

View file

@ -4,7 +4,7 @@
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypes } = require("../helpers/micromark.cjs");
const { referenceLinkImageData } = require("./cache"); const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
/** /**
* Adds an error for a label space issue. * Adds an error for a label space issue.
@ -56,11 +56,9 @@ module.exports = {
"tags": [ "whitespace", "links" ], "tags": [ "whitespace", "links" ],
"parser": "micromark", "parser": "micromark",
"function": function MD039(params, onError) { "function": function MD039(params, onError) {
const { definitions } = referenceLinkImageData(); const { definitions } = getReferenceLinkImageData();
const labels = filterByTypes( const labels = filterByTypesCached([ "label" ]).
params.parsers.micromark.tokens, filter((label) => label.parent?.type === "link");
[ "label" ]
).filter((label) => label.parent?.type === "link");
for (const label of labels) { for (const label of labels) {
const labelTexts = filterByTypes( const labelTexts = filterByTypes(
label.children, label.children,

View file

@ -3,8 +3,8 @@
"use strict"; "use strict";
const { addError, addErrorContext } = require("../helpers"); const { addError, addErrorContext } = require("../helpers");
const { filterByTypes, getTokenTextByType, tokenIfType } = const { getTokenTextByType, tokenIfType } = require("../helpers/micromark.cjs");
require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -17,10 +17,7 @@ module.exports = {
let allowed = params.config.allowed_languages; let allowed = params.config.allowed_languages;
allowed = Array.isArray(allowed) ? allowed : []; allowed = Array.isArray(allowed) ? allowed : [];
const languageOnly = !!params.config.language_only; const languageOnly = !!params.config.language_only;
const fencedCodes = filterByTypes( const fencedCodes = filterByTypesCached([ "codeFenced" ]);
params.parsers.micromark.tokens,
[ "codeFenced" ]
);
for (const fencedCode of fencedCodes) { for (const fencedCode of fencedCodes) {
const openingFence = tokenIfType(fencedCode.children[0], "codeFencedFence"); const openingFence = tokenIfType(fencedCode.children[0], "codeFencedFence");
if (openingFence) { if (openingFence) {

View file

@ -3,8 +3,8 @@
"use strict"; "use strict";
const { addErrorContext } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { getDescendantsByType, filterByTypes } = require("../helpers/micromark.cjs"); const { getDescendantsByType } = require("../helpers/micromark.cjs");
const { referenceLinkImageData } = require("./cache"); const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -14,15 +14,12 @@ module.exports = {
"tags": [ "links" ], "tags": [ "links" ],
"parser": "micromark", "parser": "micromark",
"function": function MD042(params, onError) { "function": function MD042(params, onError) {
const { definitions } = referenceLinkImageData(); const { definitions } = getReferenceLinkImageData();
const isReferenceDefinitionHash = (token) => { const isReferenceDefinitionHash = (token) => {
const definition = definitions.get(token.text.trim()); const definition = definitions.get(token.text.trim());
return (definition && (definition[1] === "#")); return (definition && (definition[1] === "#"));
}; };
const links = filterByTypes( const links = filterByTypesCached([ "link" ]);
params.parsers.micromark.tokens,
[ "link" ]
);
for (const link of links) { for (const link of links) {
const labelText = getDescendantsByType(link, [ "label", "labelText" ]); const labelText = getDescendantsByType(link, [ "label", "labelText" ]);
const reference = getDescendantsByType(link, [ "reference" ]); const reference = getDescendantsByType(link, [ "reference" ]);

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorContext, addErrorDetailIf } = require("../helpers"); const { addErrorContext, addErrorDetailIf } = require("../helpers");
const { filterByTypes, getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs"); const { getHeadingLevel, getHeadingText } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -25,11 +26,7 @@ module.exports = {
let anyHeadings = false; let anyHeadings = false;
const getExpected = () => requiredHeadings[i++] || "[None]"; const getExpected = () => requiredHeadings[i++] || "[None]";
const handleCase = (str) => (matchCase ? str : str.toLowerCase()); const handleCase = (str) => (matchCase ? str : str.toLowerCase());
const headings = filterByTypes( for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
params.parsers.micromark.tokens,
[ "atxHeading", "setextHeading" ]
);
for (const heading of headings) {
if (!hasError) { if (!hasError) {
const headingText = getHeadingText(heading); const headingText = getHeadingText(heading);
const headingLevel = getHeadingLevel(heading); const headingLevel = getHeadingLevel(heading);

View file

@ -4,6 +4,7 @@
const { addError, getHtmlAttributeRe, nextLinesRe } = require("../helpers"); const { addError, getHtmlAttributeRe, nextLinesRe } = require("../helpers");
const { filterByTypes, getHtmlTagInfo } = require("../helpers/micromark.cjs"); const { filterByTypes, getHtmlTagInfo } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const altRe = getHtmlAttributeRe("alt"); const altRe = getHtmlAttributeRe("alt");
@ -15,13 +16,8 @@ module.exports = {
"tags": [ "accessibility", "images" ], "tags": [ "accessibility", "images" ],
"parser": "micromark", "parser": "micromark",
"function": function MD045(params, onError) { "function": function MD045(params, onError) {
const micromarkTokens = params.parsers.micromark.tokens;
// Process Markdown images // Process Markdown images
const images = filterByTypes( const images = filterByTypesCached([ "image" ]);
micromarkTokens,
[ "image" ]
);
for (const image of images) { for (const image of images) {
const labelTexts = filterByTypes(image.children, [ "labelText" ]); const labelTexts = filterByTypes(image.children, [ "labelText" ]);
if (labelTexts.some((labelText) => labelText.text.length === 0)) { if (labelTexts.some((labelText) => labelText.text.length === 0)) {
@ -39,11 +35,7 @@ module.exports = {
} }
// Process HTML images // Process HTML images
const htmlTexts = filterByTypes( const htmlTexts = filterByTypesCached([ "htmlText" ], true);
micromarkTokens,
[ "htmlText" ],
true
);
for (const htmlText of htmlTexts) { for (const htmlText of htmlTexts) {
const { startColumn, startLine, text } = htmlText; const { startColumn, startLine, text } = htmlText;
const htmlTagInfo = getHtmlTagInfo(htmlText); const htmlTagInfo = getHtmlTagInfo(htmlText);

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
const tokenTypeToStyle = { const tokenTypeToStyle = {
"codeFenced": "fenced", "codeFenced": "fenced",
@ -19,11 +19,7 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD046(params, onError) { "function": function MD046(params, onError) {
let expectedStyle = String(params.config.style || "consistent"); let expectedStyle = String(params.config.style || "consistent");
const codeBlocksAndFences = filterByTypes( for (const token of filterByTypesCached([ "codeFenced", "codeIndented" ])) {
params.parsers.micromark.tokens,
[ "codeFenced", "codeIndented" ]
);
for (const token of codeBlocksAndFences) {
const { startLine, type } = token; const { startLine, type } = token;
if (expectedStyle === "consistent") { if (expectedStyle === "consistent") {
expectedStyle = tokenTypeToStyle[type]; expectedStyle = tokenTypeToStyle[type];

View file

@ -3,7 +3,8 @@
"use strict"; "use strict";
const { addErrorDetailIf, fencedCodeBlockStyleFor } = require("../helpers"); const { addErrorDetailIf, fencedCodeBlockStyleFor } = require("../helpers");
const { filterByTypes, tokenIfType } = require("../helpers/micromark.cjs"); const { tokenIfType } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -15,10 +16,7 @@ module.exports = {
"function": function MD048(params, onError) { "function": function MD048(params, onError) {
const style = String(params.config.style || "consistent"); const style = String(params.config.style || "consistent");
let expectedStyle = style; let expectedStyle = style;
const codeFenceds = filterByTypes( const codeFenceds = filterByTypesCached([ "codeFenced" ]);
params.parsers.micromark.tokens,
[ "codeFenced" ]
);
for (const codeFenced of codeFenceds) { for (const codeFenced of codeFenceds) {
const codeFencedFence = tokenIfType(codeFenced.children[0], "codeFencedFence"); const codeFencedFence = tokenIfType(codeFenced.children[0], "codeFencedFence");
if (codeFencedFence) { if (codeFencedFence) {

View file

@ -2,10 +2,9 @@
"use strict"; "use strict";
const { addError, addErrorDetailIf, getHtmlAttributeRe } = const { addError, addErrorDetailIf, getHtmlAttributeRe } = require("../helpers");
require("../helpers"); const { filterByPredicate, filterByTypes, getHtmlTagInfo } = require("../helpers/micromark.cjs");
const { filterByPredicate, filterByTypes, getHtmlTagInfo } = const { filterByTypesCached } = require("./cache");
require("../helpers/micromark.cjs");
// Regular expression for identifying HTML anchor names // Regular expression for identifying HTML anchor names
const idRe = getHtmlAttributeRe("id"); const idRe = getHtmlAttributeRe("id");
@ -69,11 +68,10 @@ module.exports = {
"tags": [ "links" ], "tags": [ "links" ],
"parser": "micromark", "parser": "micromark",
"function": function MD051(params, onError) { "function": function MD051(params, onError) {
const micromarkTokens = params.parsers.micromark.tokens;
const fragments = new Map(); const fragments = new Map();
// Process headings // Process headings
const headingTexts = filterByTypes(micromarkTokens, [ "atxHeadingText", "setextHeadingText" ]); const headingTexts = filterByTypesCached([ "atxHeadingText", "setextHeadingText" ]);
for (const headingText of headingTexts) { for (const headingText of headingTexts) {
const fragment = convertHeadingToHTMLFragment(headingText); const fragment = convertHeadingToHTMLFragment(headingText);
if (fragment !== "#") { if (fragment !== "#") {
@ -93,7 +91,7 @@ module.exports = {
} }
// Process HTML anchors // Process HTML anchors
for (const token of filterByTypes(micromarkTokens, [ "htmlText" ], true)) { for (const token of filterByTypesCached([ "htmlText" ], true)) {
const htmlTagInfo = getHtmlTagInfo(token); const htmlTagInfo = getHtmlTagInfo(token);
if (htmlTagInfo && !htmlTagInfo.close) { if (htmlTagInfo && !htmlTagInfo.close) {
const anchorMatch = idRe.exec(token.text) || const anchorMatch = idRe.exec(token.text) ||
@ -112,7 +110,7 @@ module.exports = {
[ "definition", "definitionDestinationString" ] [ "definition", "definitionDestinationString" ]
]; ];
for (const [ parentType, definitionType ] of parentChilds) { for (const [ parentType, definitionType ] of parentChilds) {
const links = filterByTypes(micromarkTokens, [ parentType ]); const links = filterByTypesCached([ parentType ]);
for (const link of links) { for (const link of links) {
const definitions = filterByTypes(link.children, [ definitionType ]); const definitions = filterByTypes(link.children, [ definitionType ]);
for (const definition of definitions) { for (const definition of definitions) {

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addError } = require("../helpers"); const { addError } = require("../helpers");
const { referenceLinkImageData } = require("./cache"); const { getReferenceLinkImageData } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -16,7 +16,7 @@ module.exports = {
"function": function MD052(params, onError) { "function": function MD052(params, onError) {
const { config, lines } = params; const { config, lines } = params;
const shortcutSyntax = config.shortcut_syntax || false; const shortcutSyntax = config.shortcut_syntax || false;
const { definitions, references, shortcuts } = referenceLinkImageData(); const { definitions, references, shortcuts } = getReferenceLinkImageData();
const entries = shortcutSyntax ? const entries = shortcutSyntax ?
[ ...references.entries(), ...shortcuts.entries() ] : [ ...references.entries(), ...shortcuts.entries() ] :
references.entries(); references.entries();

View file

@ -4,7 +4,7 @@
const { addError, ellipsify, linkReferenceDefinitionRe } = const { addError, ellipsify, linkReferenceDefinitionRe } =
require("../helpers"); require("../helpers");
const { referenceLinkImageData } = require("./cache"); const { getReferenceLinkImageData } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -17,7 +17,7 @@ module.exports = {
const ignored = new Set(params.config.ignored_definitions || [ "//" ]); const ignored = new Set(params.config.ignored_definitions || [ "//" ]);
const lines = params.lines; const lines = params.lines;
const { references, shortcuts, definitions, duplicateDefinitions } = const { references, shortcuts, definitions, duplicateDefinitions } =
referenceLinkImageData(); getReferenceLinkImageData();
const singleLineDefinition = (line) => ( const singleLineDefinition = (line) => (
line.replace(linkReferenceDefinitionRe, "").trim().length > 0 line.replace(linkReferenceDefinitionRe, "").trim().length > 0
); );

View file

@ -3,9 +3,8 @@
"use strict"; "use strict";
const { addErrorContext, nextLinesRe } = require("../helpers"); const { addErrorContext, nextLinesRe } = require("../helpers");
const { filterByTypes, filterByPredicate, getTokenTextByType } = const { filterByPredicate, getTokenTextByType } = require("../helpers/micromark.cjs");
require("../helpers/micromark.cjs"); const { getReferenceLinkImageData, filterByTypesCached } = require("./cache");
const { referenceLinkImageData } = require("./cache");
const backslashEscapeRe = /\\([!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])/g; const backslashEscapeRe = /\\([!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~])/g;
const removeBackslashEscapes = (text) => text.replace(backslashEscapeRe, "$1"); const removeBackslashEscapes = (text) => text.replace(backslashEscapeRe, "$1");
@ -40,11 +39,8 @@ module.exports = {
// Everything allowed, nothing to check // Everything allowed, nothing to check
return; return;
} }
const { definitions } = referenceLinkImageData(); const { definitions } = getReferenceLinkImageData();
const links = filterByTypes( const links = filterByTypesCached([ "autolink", "image", "link" ]);
params.parsers.micromark.tokens,
[ "autolink", "image", "link" ]
);
for (const link of links) { for (const link of links) {
let label = null; let label = null;
let destination = null; let destination = null;

View file

@ -4,6 +4,7 @@
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypes } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const whitespaceTypes = new Set([ "linePrefix", "whitespace" ]); const whitespaceTypes = new Set([ "linePrefix", "whitespace" ]);
const ignoreWhitespace = (tokens) => tokens.filter( const ignoreWhitespace = (tokens) => tokens.filter(
@ -27,10 +28,7 @@ module.exports = {
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "trailing_only")); ((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "trailing_only"));
let expectedTrailingPipe = let expectedTrailingPipe =
((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "leading_only")); ((expectedStyle !== "no_leading_or_trailing") && (expectedStyle !== "leading_only"));
const tables = filterByTypes( const tables = filterByTypesCached([ "table" ]);
params.parsers.micromark.tokens,
[ "table" ]
);
for (const table of tables) { for (const table of tables) {
const rows = filterByTypes( const rows = filterByTypes(
table.children, table.children,

View file

@ -4,6 +4,7 @@
const { addErrorDetailIf } = require("../helpers"); const { addErrorDetailIf } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypes } = require("../helpers/micromark.cjs");
const { filterByTypesCached } = require("./cache");
const makeRange = (start, end) => [ start, end - start + 1 ]; const makeRange = (start, end) => [ start, end - start + 1 ];
@ -15,10 +16,7 @@ module.exports = {
"tags": [ "table" ], "tags": [ "table" ],
"parser": "micromark", "parser": "micromark",
"function": function MD056(params, onError) { "function": function MD056(params, onError) {
const tables = filterByTypes( const tables = filterByTypesCached([ "table" ]);
params.parsers.micromark.tokens,
[ "table" ]
);
for (const table of tables) { for (const table of tables) {
const rows = filterByTypes( const rows = filterByTypes(
table.children, table.children,

View file

@ -3,7 +3,7 @@
"use strict"; "use strict";
const { addErrorContextForLine, isBlankLine } = require("../helpers"); const { addErrorContextForLine, isBlankLine } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
@ -13,12 +13,9 @@ module.exports = {
"tags": [ "table" ], "tags": [ "table" ],
"parser": "micromark", "parser": "micromark",
"function": function MD058(params, onError) { "function": function MD058(params, onError) {
const { lines, parsers } = params; const { lines } = params;
// For every table... // For every table...
const tables = filterByTypes( const tables = filterByTypesCached([ "table" ]);
parsers.micromark.tokens,
[ "table" ]
);
for (const table of tables) { for (const table of tables) {
// Look for a blank line above the table // Look for a blank line above the table
const firstIndex = table.startLine - 1; const firstIndex = table.startLine - 1;

View file

@ -921,8 +921,8 @@ test("getReferenceLinkImageData().shortcuts", (t) => {
"parser": "none", "parser": "none",
"function": "function":
() => { () => {
const { referenceLinkImageData } = require("../lib/cache"); const { getReferenceLinkImageData } = require("../lib/cache");
const { shortcuts } = referenceLinkImageData(); const { shortcuts } = getReferenceLinkImageData();
t.is(shortcuts.size, 0, [ ...shortcuts.keys() ].join(", ")); t.is(shortcuts.size, 0, [ ...shortcuts.keys() ].join(", "));
} }
} }