diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index 1b989083..cdf32a94 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -3,17 +3,12 @@ * @author Pixel998 */ -//----------------------------------------------------------------------------- -// Imports -//----------------------------------------------------------------------------- - -import { findOffsets } from "../util.js"; - //----------------------------------------------------------------------------- // Type Definitions //----------------------------------------------------------------------------- /** + * @import { SourceRange } from "@eslint/core"; * @import { Heading, Paragraph, TableCell, Text } from "mdast"; * @import { MarkdownRuleDefinition } from "../types.js"; * @typedef {"spaceInEmphasis"} NoSpaceInEmphasisMessageIds @@ -34,32 +29,8 @@ const whitespacePattern = /[ \t]/u; */ function createMarkerPattern(checkStrikethrough) { return checkStrikethrough - ? /(?<=(?\*\*\*|\*\*|\*|___|__|_|~~|~)/gu - : /(?<=(?\*\*\*|\*\*|\*|___|__|_)/gu; -} - -/** - * Finds all emphasis markers in the text. - * @param {string} text The text to search. - * @param {RegExp} pattern The marker pattern to use. - * @typedef {{marker: string, startIndex: number, endIndex: number}} EmphasisMarker - * @returns {Array} Array of emphasis markers. - */ -function findEmphasisMarkers(text, pattern) { - /** @type {Array} */ - const markers = []; - /** @type {RegExpExecArray | null} */ - let match; - - while ((match = pattern.exec(text)) !== null) { - markers.push({ - marker: match.groups.marker, - startIndex: match.index, - endIndex: match.index + match.groups.marker.length, - }); - } - - return markers; + ? /(?<=(? text"( + /** @type {Text} */ node, + ) { + const [startOffset, endOffset] = sourceCode.getRange(node); + const parentNodeStartOffset = // Parent node can be `Heading`, `Paragraph`, or `TableCell`. + sourceCode.getParent(node).position.start.offset; - return { - heading(node) { - bufferManager.enter(node); - }, - "heading > text"(node) { - bufferManager.addText(node); - }, - "heading:exit"(node) { - bufferManager.exit(node); + // Add the content of a `Text` node into the current buffer at the correct offsets. + for (let i = startOffset; i < endOffset; i++) { + buffer[i - parentNodeStartOffset] = sourceCode.text[i]; + } }, - paragraph(node) { - bufferManager.enter(node); - }, - "paragraph > text"(node) { - bufferManager.addText(node); - }, - "paragraph:exit"(node) { - bufferManager.exit(node); - }, + ":matches(heading, paragraph, tableCell):exit"( + /** @type {Heading | Paragraph | TableCell} */ node, + ) { + const maskedText = buffer.join(""); + /** @type {Map} */ + const markerGroups = new Map(); + + /** @type {RegExpExecArray | null} */ + let match; + + while ((match = markerPattern.exec(maskedText)) !== null) { + const marker = match[0]; + const startOffset = // Adjust `markerPattern` match index to the full source code. + match.index + node.position.start.offset; + const endOffset = startOffset + marker.length; + + if (!markerGroups.has(marker)) { + markerGroups.set(marker, []); + } + markerGroups.get(marker).push([startOffset, endOffset]); + } - tableCell(node) { - bufferManager.enter(node); - }, - "tableCell > text"(node) { - bufferManager.addText(node); - }, - "tableCell:exit"(node) { - bufferManager.exit(node); + for (const group of markerGroups.values()) { + for (let i = 0; i < group.length - 1; i += 2) { + const startMarker = group[i]; + reportWhitespace( + startMarker[1], + startMarker[0], + startMarker[1] + 2, + ); + + const endMarker = group[i + 1]; + reportWhitespace( + endMarker[0] - 1, + endMarker[0] - 2, + endMarker[1], + ); + } + } }, }; },