Refactor to remove helpers addErrorContextForLine and blockquotePrefixRe, add micromark helper getBlockQuotePrefixText.

This commit is contained in:
David Anson 2024-10-04 22:41:34 -07:00
parent 29ebb28f10
commit 5182911acc
6 changed files with 170 additions and 152 deletions

View file

@ -30,10 +30,6 @@ const inlineCommentStartRe =
/(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/gi; /(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/gi;
module.exports.inlineCommentStartRe = inlineCommentStartRe; module.exports.inlineCommentStartRe = inlineCommentStartRe;
// Regular expression for blockquote prefixes
const blockquotePrefixRe = /^[>\s]*/;
module.exports.blockquotePrefixRe = blockquotePrefixRe;
// Regular expression for link reference definitions // Regular expression for link reference definitions
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/; const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe; module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
@ -358,34 +354,6 @@ function addErrorContext(
} }
module.exports.addErrorContext = addErrorContext; module.exports.addErrorContext = addErrorContext;
/**
* Adds an error object with context for a construct missing a blank line.
*
* @param {Object} onError RuleOnError instance.
* @param {string[]} lines Lines of Markdown content.
* @param {number} lineIndex Line index of line.
* @param {number} [lineNumber] Line number for override.
* @returns {void}
*/
function addErrorContextForLine(onError, lines, lineIndex, lineNumber) {
const line = lines[lineIndex];
// @ts-ignore
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
addErrorContext(
onError,
lineIndex + 1,
line.trim(),
undefined,
undefined,
undefined,
{
lineNumber,
"insertText": `${quotePrefix}\n`
}
);
}
module.exports.addErrorContextForLine = addErrorContextForLine;
/** /**
* Defines a range within a file (start line/column to end line/column, subset of MicromarkToken). * Defines a range within a file (start line/column to end line/column, subset of MicromarkToken).
* *
@ -1004,6 +972,25 @@ function filterByTypes(tokens, types, htmlFlow) {
return filterByPredicate(tokens, predicate); return filterByPredicate(tokens, predicate);
} }
/**
* Gets the blockquote prefix text (if any) for the specified line number.
*
* @param {Token[]} tokens Micromark tokens.
* @param {number} lineNumber Line number to examine.
* @param {number} [count] Number of times to repeat.
* @returns {string} Blockquote prefix text.
*/
function getBlockQuotePrefixText(tokens, lineNumber, count = 1) {
return filterByTypes(tokens, [ "blockQuotePrefix", "linePrefix" ])
.filter((prefix) => prefix.startLine === lineNumber)
.map((prefix) => prefix.text)
.join("")
.trimEnd()
// eslint-disable-next-line unicorn/prefer-spread
.concat("\n")
.repeat(count);
};
/** /**
* Gets a list of nested Micromark token descendants by type path. * Gets a list of nested Micromark token descendants by type path.
* *
@ -1138,6 +1125,7 @@ module.exports = {
addRangeToSet, addRangeToSet,
filterByPredicate, filterByPredicate,
filterByTypes, filterByTypes,
getBlockQuotePrefixText,
getDescendantsByType, getDescendantsByType,
getHeadingLevel, getHeadingLevel,
getHeadingStyle, getHeadingStyle,
@ -4261,8 +4249,8 @@ module.exports = {
const { addErrorDetailIf, blockquotePrefixRe, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { addErrorDetailIf, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { getHeadingLevel } = __webpack_require__(/*! ../helpers/micromark-helpers.cjs */ "../helpers/micromark-helpers.cjs"); const { getBlockQuotePrefixText, getHeadingLevel } = __webpack_require__(/*! ../helpers/micromark-helpers.cjs */ "../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); const { filterByTypesCached } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
const defaultLines = 1; const defaultLines = 1;
@ -4280,15 +4268,6 @@ const getLinesFunction = (linesParam) => {
return () => lines; return () => lines;
}; };
const getBlockQuote = (str, count) => (
(str || "")
.match(blockquotePrefixRe)[0]
.trimEnd()
// eslint-disable-next-line unicorn/prefer-spread
.concat("\n")
.repeat(count)
);
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
module.exports = { module.exports = {
@ -4300,6 +4279,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 blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) { for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
const { startLine, endLine } = heading; const { startLine, endLine } = heading;
const line = lines[startLine - 1].trim(); const line = lines[startLine - 1].trim();
@ -4324,8 +4304,9 @@ module.exports = {
line, line,
undefined, undefined,
{ {
"insertText": getBlockQuote( "insertText": getBlockQuotePrefixText(
lines[startLine - 2], blockQuotePrefixes,
startLine - 1,
linesAbove - actualAbove linesAbove - actualAbove
) )
} }
@ -4353,8 +4334,9 @@ module.exports = {
undefined, undefined,
{ {
"lineNumber": endLine + 1, "lineNumber": endLine + 1,
"insertText": getBlockQuote( "insertText": getBlockQuotePrefixText(
lines[endLine], blockQuotePrefixes,
endLine + 1,
linesBelow - actualBelow linesBelow - actualBelow
) )
} }
@ -4934,8 +4916,9 @@ module.exports = {
const { addErrorContextForLine, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { addErrorContext, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { filterByPredicate, nonContentTokens } = __webpack_require__(/*! ../helpers/micromark-helpers.cjs */ "../helpers/micromark-helpers.cjs"); const { filterByPredicate, getBlockQuotePrefixText, nonContentTokens } = __webpack_require__(/*! ../helpers/micromark-helpers.cjs */ "../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
const isList = (token) => ( const isList = (token) => (
(token.type === "listOrdered") || (token.type === "listUnordered") (token.type === "listOrdered") || (token.type === "listUnordered")
@ -4950,6 +4933,7 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD032(params, onError) { "function": function MD032(params, onError) {
const { lines, parsers } = params; const { lines, parsers } = params;
const blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
// For every top-level list... // For every top-level list...
const topLevelLists = filterByPredicate( const topLevelLists = filterByPredicate(
@ -4962,13 +4946,18 @@ module.exports = {
for (const list of topLevelLists) { for (const list of topLevelLists) {
// Look for a blank line above the list // Look for a blank line above the list
const firstIndex = list.startLine - 1; const firstLineNumber = list.startLine;
if (!isBlankLine(lines[firstIndex - 1])) { if (!isBlankLine(lines[firstLineNumber - 2])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore firstLineNumber,
lines, lines[firstLineNumber - 1].trim(),
firstIndex undefined,
undefined,
undefined,
{
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, firstLineNumber)
}
); );
} }
@ -4983,14 +4972,19 @@ module.exports = {
} }
// Look for a blank line below the list // Look for a blank line below the list
const lastIndex = endLine - 1; const lastLineNumber = endLine;
if (!isBlankLine(lines[lastIndex + 1])) { if (!isBlankLine(lines[lastLineNumber])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore lastLineNumber,
lines, lines[lastLineNumber - 1].trim(),
lastIndex, undefined,
lastIndex + 2 undefined,
undefined,
{
"lineNumber": lastLineNumber + 1,
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, lastLineNumber)
}
); );
} }
} }
@ -6864,7 +6858,8 @@ module.exports = {
const { addErrorContextForLine, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { addErrorContext, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { getBlockQuotePrefixText } = __webpack_require__(/*! ../helpers/micromark-helpers.cjs */ "../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); const { filterByTypesCached } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
@ -6876,28 +6871,42 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD058(params, onError) { "function": function MD058(params, onError) {
const { lines } = params; const { lines } = params;
const blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
// For every table... // For every table...
const tables = filterByTypesCached([ "table" ]); const tables = filterByTypesCached([ "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 firstLineNumber = table.startLine;
if (!isBlankLine(lines[firstIndex - 1])) { if (!isBlankLine(lines[firstLineNumber - 2])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore firstLineNumber,
lines, lines[firstLineNumber - 1].trim(),
firstIndex undefined,
undefined,
undefined,
{
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, firstLineNumber)
}
); );
} }
// Look for a blank line below the table // Look for a blank line below the table
const lastIndex = table.endLine - 1; const lastLineNumber = table.endLine;
if (!isBlankLine(lines[lastIndex + 1])) { if (!isBlankLine(lines[lastLineNumber])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore lastLineNumber,
lines, lines[lastLineNumber - 1].trim(),
lastIndex, undefined,
lastIndex + 2 undefined,
undefined,
{
"lineNumber": lastLineNumber + 1,
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, lastLineNumber)
}
); );
} }
} }

View file

@ -18,10 +18,6 @@ const inlineCommentStartRe =
/(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/gi; /(<!--\s*markdownlint-(disable|enable|capture|restore|disable-file|enable-file|disable-line|disable-next-line|configure-file))(?:\s|-->)/gi;
module.exports.inlineCommentStartRe = inlineCommentStartRe; module.exports.inlineCommentStartRe = inlineCommentStartRe;
// Regular expression for blockquote prefixes
const blockquotePrefixRe = /^[>\s]*/;
module.exports.blockquotePrefixRe = blockquotePrefixRe;
// Regular expression for link reference definitions // Regular expression for link reference definitions
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/; const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/;
module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe; module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
@ -346,34 +342,6 @@ function addErrorContext(
} }
module.exports.addErrorContext = addErrorContext; module.exports.addErrorContext = addErrorContext;
/**
* Adds an error object with context for a construct missing a blank line.
*
* @param {Object} onError RuleOnError instance.
* @param {string[]} lines Lines of Markdown content.
* @param {number} lineIndex Line index of line.
* @param {number} [lineNumber] Line number for override.
* @returns {void}
*/
function addErrorContextForLine(onError, lines, lineIndex, lineNumber) {
const line = lines[lineIndex];
// @ts-ignore
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
addErrorContext(
onError,
lineIndex + 1,
line.trim(),
undefined,
undefined,
undefined,
{
lineNumber,
"insertText": `${quotePrefix}\n`
}
);
}
module.exports.addErrorContextForLine = addErrorContextForLine;
/** /**
* Defines a range within a file (start line/column to end line/column, subset of MicromarkToken). * Defines a range within a file (start line/column to end line/column, subset of MicromarkToken).
* *

View file

@ -133,6 +133,25 @@ function filterByTypes(tokens, types, htmlFlow) {
return filterByPredicate(tokens, predicate); return filterByPredicate(tokens, predicate);
} }
/**
* Gets the blockquote prefix text (if any) for the specified line number.
*
* @param {Token[]} tokens Micromark tokens.
* @param {number} lineNumber Line number to examine.
* @param {number} [count] Number of times to repeat.
* @returns {string} Blockquote prefix text.
*/
function getBlockQuotePrefixText(tokens, lineNumber, count = 1) {
return filterByTypes(tokens, [ "blockQuotePrefix", "linePrefix" ])
.filter((prefix) => prefix.startLine === lineNumber)
.map((prefix) => prefix.text)
.join("")
.trimEnd()
// eslint-disable-next-line unicorn/prefer-spread
.concat("\n")
.repeat(count);
};
/** /**
* Gets a list of nested Micromark token descendants by type path. * Gets a list of nested Micromark token descendants by type path.
* *
@ -267,6 +286,7 @@ module.exports = {
addRangeToSet, addRangeToSet,
filterByPredicate, filterByPredicate,
filterByTypes, filterByTypes,
getBlockQuotePrefixText,
getDescendantsByType, getDescendantsByType,
getHeadingLevel, getHeadingLevel,
getHeadingStyle, getHeadingStyle,

View file

@ -2,8 +2,8 @@
"use strict"; "use strict";
const { addErrorDetailIf, blockquotePrefixRe, isBlankLine } = require("../helpers"); const { addErrorDetailIf, isBlankLine } = require("../helpers");
const { getHeadingLevel } = require("../helpers/micromark-helpers.cjs"); const { getBlockQuotePrefixText, getHeadingLevel } = require("../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = require("./cache"); const { filterByTypesCached } = require("./cache");
const defaultLines = 1; const defaultLines = 1;
@ -21,15 +21,6 @@ const getLinesFunction = (linesParam) => {
return () => lines; return () => lines;
}; };
const getBlockQuote = (str, count) => (
(str || "")
.match(blockquotePrefixRe)[0]
.trimEnd()
// eslint-disable-next-line unicorn/prefer-spread
.concat("\n")
.repeat(count)
);
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
/** @type import("./markdownlint").Rule */ /** @type import("./markdownlint").Rule */
module.exports = { module.exports = {
@ -41,6 +32,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 blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) { for (const heading of filterByTypesCached([ "atxHeading", "setextHeading" ])) {
const { startLine, endLine } = heading; const { startLine, endLine } = heading;
const line = lines[startLine - 1].trim(); const line = lines[startLine - 1].trim();
@ -65,8 +57,9 @@ module.exports = {
line, line,
undefined, undefined,
{ {
"insertText": getBlockQuote( "insertText": getBlockQuotePrefixText(
lines[startLine - 2], blockQuotePrefixes,
startLine - 1,
linesAbove - actualAbove linesAbove - actualAbove
) )
} }
@ -94,8 +87,9 @@ module.exports = {
undefined, undefined,
{ {
"lineNumber": endLine + 1, "lineNumber": endLine + 1,
"insertText": getBlockQuote( "insertText": getBlockQuotePrefixText(
lines[endLine], blockQuotePrefixes,
endLine + 1,
linesBelow - actualBelow linesBelow - actualBelow
) )
} }

View file

@ -2,8 +2,9 @@
"use strict"; "use strict";
const { addErrorContextForLine, isBlankLine } = require("../helpers"); const { addErrorContext, isBlankLine } = require("../helpers");
const { filterByPredicate, nonContentTokens } = require("../helpers/micromark-helpers.cjs"); const { filterByPredicate, getBlockQuotePrefixText, nonContentTokens } = require("../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = require("./cache");
const isList = (token) => ( const isList = (token) => (
(token.type === "listOrdered") || (token.type === "listUnordered") (token.type === "listOrdered") || (token.type === "listUnordered")
@ -18,6 +19,7 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD032(params, onError) { "function": function MD032(params, onError) {
const { lines, parsers } = params; const { lines, parsers } = params;
const blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
// For every top-level list... // For every top-level list...
const topLevelLists = filterByPredicate( const topLevelLists = filterByPredicate(
@ -30,13 +32,18 @@ module.exports = {
for (const list of topLevelLists) { for (const list of topLevelLists) {
// Look for a blank line above the list // Look for a blank line above the list
const firstIndex = list.startLine - 1; const firstLineNumber = list.startLine;
if (!isBlankLine(lines[firstIndex - 1])) { if (!isBlankLine(lines[firstLineNumber - 2])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore firstLineNumber,
lines, lines[firstLineNumber - 1].trim(),
firstIndex undefined,
undefined,
undefined,
{
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, firstLineNumber)
}
); );
} }
@ -51,14 +58,19 @@ module.exports = {
} }
// Look for a blank line below the list // Look for a blank line below the list
const lastIndex = endLine - 1; const lastLineNumber = endLine;
if (!isBlankLine(lines[lastIndex + 1])) { if (!isBlankLine(lines[lastLineNumber])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore lastLineNumber,
lines, lines[lastLineNumber - 1].trim(),
lastIndex, undefined,
lastIndex + 2 undefined,
undefined,
{
"lineNumber": lastLineNumber + 1,
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, lastLineNumber)
}
); );
} }
} }

View file

@ -2,7 +2,8 @@
"use strict"; "use strict";
const { addErrorContextForLine, isBlankLine } = require("../helpers"); const { addErrorContext, isBlankLine } = require("../helpers");
const { getBlockQuotePrefixText } = require("../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = require("./cache"); const { filterByTypesCached } = require("./cache");
// eslint-disable-next-line jsdoc/valid-types // eslint-disable-next-line jsdoc/valid-types
@ -14,28 +15,42 @@ module.exports = {
"parser": "micromark", "parser": "micromark",
"function": function MD058(params, onError) { "function": function MD058(params, onError) {
const { lines } = params; const { lines } = params;
const blockQuotePrefixes = filterByTypesCached([ "blockQuotePrefix", "linePrefix" ]);
// For every table... // For every table...
const tables = filterByTypesCached([ "table" ]); const tables = filterByTypesCached([ "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 firstLineNumber = table.startLine;
if (!isBlankLine(lines[firstIndex - 1])) { if (!isBlankLine(lines[firstLineNumber - 2])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore firstLineNumber,
lines, lines[firstLineNumber - 1].trim(),
firstIndex undefined,
undefined,
undefined,
{
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, firstLineNumber)
}
); );
} }
// Look for a blank line below the table // Look for a blank line below the table
const lastIndex = table.endLine - 1; const lastLineNumber = table.endLine;
if (!isBlankLine(lines[lastIndex + 1])) { if (!isBlankLine(lines[lastLineNumber])) {
addErrorContextForLine( addErrorContext(
onError, onError,
// @ts-ignore lastLineNumber,
lines, lines[lastLineNumber - 1].trim(),
lastIndex, undefined,
lastIndex + 2 undefined,
undefined,
{
"lineNumber": lastLineNumber + 1,
"insertText": getBlockQuotePrefixText(blockQuotePrefixes, lastLineNumber)
}
); );
} }
} }