// @ts-check import { addError } from "../helpers/helpers.cjs"; import { filterByPredicate, inHtmlFlow } from "../helpers/micromark-helpers.cjs"; /** @type {import("markdownlint").Rule} */ export default { "names": [ "MD037", "no-space-in-emphasis" ], "description": "Spaces inside emphasis markers", "tags": [ "whitespace", "emphasis" ], "parser": "micromark", "function": function MD037(params, onError) { // Initialize variables const { lines, parsers } = params; const emphasisTokensByMarker = new Map(); for (const marker of [ "_", "__", "___", "*", "**", "***" ]) { emphasisTokensByMarker.set(marker, []); } const tokens = filterByPredicate( parsers.micromark.tokens, (token) => token.children.some((child) => child.type === "data") ); for (const token of tokens) { // Build lists of bare tokens for each emphasis marker type for (const emphasisTokens of emphasisTokensByMarker.values()) { emphasisTokens.length = 0; } for (const child of token.children) { const { text, type } = child; if ((type === "data") && (text.length <= 3)) { const emphasisTokens = emphasisTokensByMarker.get(text); if (emphasisTokens && !inHtmlFlow(child)) { emphasisTokens.push(child); } } } // Process bare tokens for each emphasis marker type for (const entry of emphasisTokensByMarker.entries()) { const [ marker, emphasisTokens ] = entry; for (let i = 0; i + 1 < emphasisTokens.length; i += 2) { // Process start token of start/end pair const startToken = emphasisTokens[i]; const startLine = lines[startToken.startLine - 1]; const startSlice = startLine.slice(startToken.endColumn - 1); const startMatch = startSlice.match(/^\s+\S/); if (startMatch) { const [ startSpaceCharacter ] = startMatch; const startContext = `${marker}${startSpaceCharacter}`; addError( onError, startToken.startLine, undefined, startContext, [ startToken.startColumn, startContext.length ], { "editColumn": startToken.endColumn, "deleteCount": startSpaceCharacter.length - 1 } ); } // Process end token of start/end pair const endToken = emphasisTokens[i + 1]; const endLine = lines[endToken.startLine - 1]; const endSlice = endLine.slice(0, endToken.startColumn - 1); const endMatch = endSlice.match(/\S\s+$/); if (endMatch) { const [ endSpaceCharacter ] = endMatch; const endContext = `${endSpaceCharacter}${marker}`; addError( onError, endToken.startLine, undefined, endContext, [ endToken.endColumn - endContext.length, endContext.length ], { "editColumn": endToken.startColumn - (endSpaceCharacter.length - 1), "deleteCount": endSpaceCharacter.length - 1 } ); } } } } } };