Reimplement MD028/no-blanks-blockquote using micromark tokens.

This commit is contained in:
David Anson 2024-02-18 16:46:13 -08:00
parent 89eef68dbd
commit f5b5773b50
4 changed files with 94 additions and 30 deletions

View file

@ -1473,6 +1473,28 @@ function filterByTypes(tokens, types) {
return filterByPredicate(tokens, predicate);
}
/**
* Gets all sibling token groups for a list of Micromark tokens.
*
* @param {Token[]} tokens Micromark tokens.
* @returns {Token[][]} Sibling token groups.
*/
function getSiblingTokens(tokens) {
const result = [];
const queue = [ tokens ];
// eslint-disable-next-line init-declarations
let current;
while ((current = queue.shift())) {
result.push(current);
for (const token of current) {
if (token.children.length > 0) {
queue.push(token.children);
}
}
}
return result;
}
/**
* Gets the heading level of a Micromark heading tokan.
*
@ -1597,6 +1619,7 @@ module.exports = {
getHeadingLevel,
getHtmlTagInfo,
getMicromarkEvents,
getSiblingLists: getSiblingTokens,
getTokenParentOfType,
getTokenTextByType,
inHtmlFlow,
@ -4464,7 +4487,6 @@ const { addError, allPunctuationNoQuestion, endOfLineGemojiCodeRe,
endOfLineHtmlEntityRe, escapeForRegExp } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { filterByTypes } = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs");
module.exports = {
"names": [ "MD026", "no-trailing-punctuation" ],
"description": "Trailing punctuation in heading",
@ -4589,27 +4611,37 @@ module.exports = {
const { addError } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { getSiblingLists } = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs");
module.exports = {
"names": [ "MD028", "no-blanks-blockquote" ],
"description": "Blank line inside blockquote",
"tags": [ "blockquote", "whitespace" ],
"function": function MD028(params, onError) {
let prevToken = {};
let prevLineNumber = null;
for (const token of params.parsers.markdownit.tokens) {
if ((token.type === "blockquote_open") &&
(prevToken.type === "blockquote_close")) {
for (
let lineNumber = prevLineNumber;
lineNumber < token.lineNumber;
lineNumber++) {
for (const siblings of getSiblingLists(params.parsers.micromark.tokens)) {
let errorLineNumbers = null;
for (const sibling of siblings) {
switch (sibling.type) {
case "blockQuote":
for (const lineNumber of (errorLineNumbers || [])) {
addError(onError, lineNumber);
}
errorLineNumbers = [];
break;
case "lineEnding":
case "linePrefix":
case "listItemIndent":
// Ignore
break;
case "lineEndingBlank":
if (errorLineNumbers) {
errorLineNumbers.push(sibling.startLine);
}
break;
default:
errorLineNumbers = null;
break;
}
prevToken = token;
if (token.type === "blockquote_open") {
prevLineNumber = token.map[1] + 1;
}
}
}

View file

@ -295,6 +295,28 @@ function filterByTypes(tokens, types) {
return filterByPredicate(tokens, predicate);
}
/**
* Gets all sibling token groups for a list of Micromark tokens.
*
* @param {Token[]} tokens Micromark tokens.
* @returns {Token[][]} Sibling token groups.
*/
function getSiblingTokens(tokens) {
const result = [];
const queue = [ tokens ];
// eslint-disable-next-line init-declarations
let current;
while ((current = queue.shift())) {
result.push(current);
for (const token of current) {
if (token.children.length > 0) {
queue.push(token.children);
}
}
}
return result;
}
/**
* Gets the heading level of a Micromark heading tokan.
*
@ -419,6 +441,7 @@ module.exports = {
getHeadingLevel,
getHtmlTagInfo,
getMicromarkEvents,
getSiblingLists: getSiblingTokens,
getTokenParentOfType,
getTokenTextByType,
inHtmlFlow,

View file

@ -6,7 +6,6 @@ const { addError, allPunctuationNoQuestion, endOfLineGemojiCodeRe,
endOfLineHtmlEntityRe, escapeForRegExp } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs");
module.exports = {
"names": [ "MD026", "no-trailing-punctuation" ],
"description": "Trailing punctuation in heading",

View file

@ -3,27 +3,37 @@
"use strict";
const { addError } = require("../helpers");
const { getSiblingLists } = require("../helpers/micromark.cjs");
module.exports = {
"names": [ "MD028", "no-blanks-blockquote" ],
"description": "Blank line inside blockquote",
"tags": [ "blockquote", "whitespace" ],
"function": function MD028(params, onError) {
let prevToken = {};
let prevLineNumber = null;
for (const token of params.parsers.markdownit.tokens) {
if ((token.type === "blockquote_open") &&
(prevToken.type === "blockquote_close")) {
for (
let lineNumber = prevLineNumber;
lineNumber < token.lineNumber;
lineNumber++) {
for (const siblings of getSiblingLists(params.parsers.micromark.tokens)) {
let errorLineNumbers = null;
for (const sibling of siblings) {
switch (sibling.type) {
case "blockQuote":
for (const lineNumber of (errorLineNumbers || [])) {
addError(onError, lineNumber);
}
errorLineNumbers = [];
break;
case "lineEnding":
case "linePrefix":
case "listItemIndent":
// Ignore
break;
case "lineEndingBlank":
if (errorLineNumbers) {
errorLineNumbers.push(sibling.startLine);
}
break;
default:
errorLineNumbers = null;
break;
}
prevToken = token;
if (token.type === "blockquote_open") {
prevLineNumber = token.map[1] + 1;
}
}
}