From 6ee8076d2e2173aead90bc091da824b5a4503885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 21:00:26 +0900 Subject: [PATCH 01/10] refactor: use `getLocFromIndex` in `no-space-in-emphasis` --- src/rules/no-space-in-emphasis.js | 206 +++++++++--------------------- 1 file changed, 60 insertions(+), 146 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index 1b989083..2a9987da 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -3,12 +3,6 @@ * @author Pixel998 */ -//----------------------------------------------------------------------------- -// Imports -//----------------------------------------------------------------------------- - -import { findOffsets } from "../util.js"; - //----------------------------------------------------------------------------- // Type Definitions //----------------------------------------------------------------------------- @@ -19,6 +13,7 @@ import { findOffsets } from "../util.js"; * @typedef {"spaceInEmphasis"} NoSpaceInEmphasisMessageIds * @typedef {[{ checkStrikethrough?: boolean }]} NoSpaceInEmphasisOptions * @typedef {MarkdownRuleDefinition<{ RuleOptions: NoSpaceInEmphasisOptions, MessageIds: NoSpaceInEmphasisMessageIds }>} NoSpaceInEmphasisRuleDefinition + * @typedef {{marker: string, startIndex: number, endIndex: number}} EmphasisMarker */ //----------------------------------------------------------------------------- @@ -42,7 +37,6 @@ function createMarkerPattern(checkStrikethrough) { * 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) { @@ -107,182 +101,102 @@ export default { const [{ checkStrikethrough }] = context.options; const markerPattern = createMarkerPattern(checkStrikethrough); + /** @type {{ buffer: string[], startOffset: number } | null} */ + let bufferState = null; + /** * Reports a surrounding-space violation if present. * @param {Object} params Options for the report arguments. - * @param {string} params.originalText The original text of the node. * @param {number} params.checkIndex Character index to test for whitespace. * @param {number} params.highlightStartIndex Start index for highlighting. * @param {number} params.highlightEndIndex End index for highlighting. - * @param {number} params.removeIndex Absolute index of the space to remove. - * @param {number} params.nodeStartLine The starting line number for the node. - * @param {number} params.nodeStartColumn The starting column number for the node. * @returns {void} */ function reportWhitespace({ - originalText, checkIndex, highlightStartIndex, highlightEndIndex, - removeIndex, - nodeStartLine, - nodeStartColumn, }) { - if (whitespacePattern.test(originalText[checkIndex])) { - const { - lineOffset: startLineOffset, - columnOffset: startColumnOffset, - } = findOffsets(originalText, highlightStartIndex); - const { - lineOffset: endLineOffset, - columnOffset: endColumnOffset, - } = findOffsets(originalText, highlightEndIndex); - + if (whitespacePattern.test(sourceCode.text[checkIndex])) { context.report({ loc: { - start: { - line: nodeStartLine + startLineOffset, - column: nodeStartColumn + startColumnOffset, - }, - end: { - line: nodeStartLine + endLineOffset, - column: nodeStartColumn + endColumnOffset, - }, + start: sourceCode.getLocFromIndex(highlightStartIndex), + end: sourceCode.getLocFromIndex(highlightEndIndex), }, messageId: "spaceInEmphasis", fix(fixer) { - return fixer.removeRange([ - removeIndex, - removeIndex + 1, - ]); + return fixer.removeRange([checkIndex, checkIndex + 1]); }, }); } } - /** - * Checks a given node for emphasis markers with surrounding spaces. - * @param {Heading|Paragraph|TableCell} node The node to check. - * @param {string} maskedText The masked text preserving only direct text content. - * @returns {void} - */ - function checkEmphasis(node, maskedText) { - const originalText = sourceCode.getText(node); - const markers = findEmphasisMarkers(maskedText, markerPattern); - const nodeStartLine = node.position.start.line; - const nodeStartColumn = node.position.start.column; - const nodeStartOffset = node.position.start.offset; - - const markerGroups = new Map(); - for (const marker of markers) { - if (!markerGroups.has(marker.marker)) { - markerGroups.set(marker.marker, []); - } - markerGroups.get(marker.marker).push(marker); - } - - for (const group of markerGroups.values()) { - for (let i = 0; i < group.length - 1; i += 2) { - const startMarker = group[i]; - reportWhitespace({ - originalText, - checkIndex: startMarker.endIndex, - highlightStartIndex: startMarker.startIndex, - highlightEndIndex: startMarker.endIndex + 2, - removeIndex: nodeStartOffset + startMarker.endIndex, - nodeStartLine, - nodeStartColumn, - }); - - const endMarker = group[i + 1]; - reportWhitespace({ - originalText, - checkIndex: endMarker.startIndex - 1, - highlightStartIndex: endMarker.startIndex - 2, - highlightEndIndex: endMarker.endIndex, - removeIndex: nodeStartOffset + endMarker.startIndex - 1, - nodeStartLine, - nodeStartColumn, - }); - } - } - } - - /** - * Manager for building a masked character array for a node's direct text content. - * @typedef {{ buffer: string[], startOffset: number }} BufferState - */ - const bufferManager = { - /** @type {BufferState | null} */ - state: null, - - /** - * Initialize state with a whitespace-masked character buffer for the node. - * @param {Heading|Paragraph|TableCell} node Heading, Paragraph, or TableCell node to enter. - * @returns {void} - */ - enter(node) { + return { + "heading, paragraph, tableCell"( + /** @type {Heading | Paragraph | TableCell} */ node, + ) { + // Initialize state with a whitespace-masked character buffer for the node. const [startOffset, endOffset] = sourceCode.getRange(node); - this.state = { + bufferState = { buffer: new Array(endOffset - startOffset).fill(" "), startOffset, }; }, - /** - * Add the content of a Text node into the current buffer at the correct offsets. - * @param {Text} node Text node whose characters will be copied into the buffer. - * @returns {void} - */ - addText(node) { + ":matches(heading, paragraph, tableCell) > text"( + /** @type {Text} */ node, + ) { + // Add the content of a Text node into the current buffer at the correct offsets. const start = - node.position.start.offset - this.state.startOffset; + node.position.start.offset - bufferState.startOffset; const text = sourceCode.getText(node); for (let i = 0; i < text.length; i++) { - this.state.buffer[start + i] = text[i]; + bufferState.buffer[start + i] = text[i]; } }, - /** - * Join the character buffer into a masked string, run checks, then clear state. - * @param {Heading|Paragraph|TableCell} node Heading, Paragraph, or TableCell node to exit. - * @returns {void} - */ - exit(node) { - checkEmphasis(node, this.state.buffer.join("")); - this.state = null; - }, - }; - - return { - heading(node) { - bufferManager.enter(node); - }, - "heading > text"(node) { - bufferManager.addText(node); - }, - "heading:exit"(node) { - bufferManager.exit(node); - }, + ":matches(heading, paragraph, tableCell):exit"( + /** @type {Heading | Paragraph | TableCell} */ node, + ) { + // Join the character buffer into a masked string, run checks, then clear state. + const maskedText = bufferState.buffer.join(""); + const markers = findEmphasisMarkers(maskedText, markerPattern); + const nodeStartOffset = node.position.start.offset; + + /** @type {Map} */ + const markerGroups = new Map(); + + for (const marker of markers) { + if (!markerGroups.has(marker.marker)) { + markerGroups.set(marker.marker, []); + } + markerGroups.get(marker.marker).push(marker); + } - paragraph(node) { - bufferManager.enter(node); - }, - "paragraph > text"(node) { - bufferManager.addText(node); - }, - "paragraph: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({ + checkIndex: nodeStartOffset + startMarker.endIndex, + highlightStartIndex: + nodeStartOffset + startMarker.startIndex, + highlightEndIndex: + nodeStartOffset + startMarker.endIndex + 2, + }); + + const endMarker = group[i + 1]; + reportWhitespace({ + checkIndex: + nodeStartOffset + endMarker.startIndex - 1, + highlightStartIndex: + nodeStartOffset + endMarker.startIndex - 2, + highlightEndIndex: + nodeStartOffset + endMarker.endIndex, + }); + } + } - tableCell(node) { - bufferManager.enter(node); - }, - "tableCell > text"(node) { - bufferManager.addText(node); - }, - "tableCell:exit"(node) { - bufferManager.exit(node); + bufferState = null; }, }; }, From b94253047fa2cf4d204ab9939f4851e65a2911e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 22:39:40 +0900 Subject: [PATCH 02/10] wip: simplify --- src/rules/no-space-in-emphasis.js | 65 ++++++++++++------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index 2a9987da..1ac5f9e4 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -33,29 +33,6 @@ function createMarkerPattern(checkStrikethrough) { : /(?<=(?\*\*\*|\*\*|\*|___|__|_)/gu; } -/** - * Finds all emphasis markers in the text. - * @param {string} text The text to search. - * @param {RegExp} pattern The marker pattern to use. - * @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; -} - //----------------------------------------------------------------------------- // Rule Definition //----------------------------------------------------------------------------- @@ -132,10 +109,10 @@ export default { } return { + // Initialize `bufferState` with a whitespace-masked character buffer for the node. "heading, paragraph, tableCell"( /** @type {Heading | Paragraph | TableCell} */ node, ) { - // Initialize state with a whitespace-masked character buffer for the node. const [startOffset, endOffset] = sourceCode.getRange(node); bufferState = { buffer: new Array(endOffset - startOffset).fill(" "), @@ -143,10 +120,10 @@ export default { }; }, + // Add the content of a `Text` node into the current buffer at the correct offsets. ":matches(heading, paragraph, tableCell) > text"( /** @type {Text} */ node, ) { - // Add the content of a Text node into the current buffer at the correct offsets. const start = node.position.start.offset - bufferState.startOffset; const text = sourceCode.getText(node); @@ -155,17 +132,30 @@ export default { } }, + // Join the character buffer into a masked string, run checks, then clear state. ":matches(heading, paragraph, tableCell):exit"( /** @type {Heading | Paragraph | TableCell} */ node, ) { - // Join the character buffer into a masked string, run checks, then clear state. const maskedText = bufferState.buffer.join(""); - const markers = findEmphasisMarkers(maskedText, markerPattern); - const nodeStartOffset = node.position.start.offset; - + /** @type {EmphasisMarker[]} */ + const markers = []; /** @type {Map} */ const markerGroups = new Map(); + /** @type {RegExpExecArray | null} */ + let match; + + while ((match = markerPattern.exec(maskedText)) !== null) { + const startIndex = match.index + node.position.start.offset; + const endIndex = startIndex + match.groups.marker.length; + + markers.push({ + marker: match.groups.marker, + startIndex, + endIndex, + }); + } + for (const marker of markers) { if (!markerGroups.has(marker.marker)) { markerGroups.set(marker.marker, []); @@ -177,21 +167,16 @@ export default { for (let i = 0; i < group.length - 1; i += 2) { const startMarker = group[i]; reportWhitespace({ - checkIndex: nodeStartOffset + startMarker.endIndex, - highlightStartIndex: - nodeStartOffset + startMarker.startIndex, - highlightEndIndex: - nodeStartOffset + startMarker.endIndex + 2, + checkIndex: startMarker.endIndex, + highlightStartIndex: startMarker.startIndex, + highlightEndIndex: startMarker.endIndex + 2, }); const endMarker = group[i + 1]; reportWhitespace({ - checkIndex: - nodeStartOffset + endMarker.startIndex - 1, - highlightStartIndex: - nodeStartOffset + endMarker.startIndex - 2, - highlightEndIndex: - nodeStartOffset + endMarker.endIndex, + checkIndex: endMarker.startIndex - 1, + highlightStartIndex: endMarker.startIndex - 2, + highlightEndIndex: endMarker.endIndex, }); } } From c45cefed8cca7b622e0abdd7165308b616ea6e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 22:42:28 +0900 Subject: [PATCH 03/10] wip: simplify --- src/rules/no-space-in-emphasis.js | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index 1ac5f9e4..1ef17d10 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -83,17 +83,16 @@ export default { /** * Reports a surrounding-space violation if present. - * @param {Object} params Options for the report arguments. - * @param {number} params.checkIndex Character index to test for whitespace. - * @param {number} params.highlightStartIndex Start index for highlighting. - * @param {number} params.highlightEndIndex End index for highlighting. + * @param {number} checkIndex Character index to test for whitespace. + * @param {number} highlightStartIndex Start index for highlighting. + * @param {number} highlightEndIndex End index for highlighting. * @returns {void} */ - function reportWhitespace({ + function reportWhitespace( checkIndex, highlightStartIndex, highlightEndIndex, - }) { + ) { if (whitespacePattern.test(sourceCode.text[checkIndex])) { context.report({ loc: { @@ -166,18 +165,18 @@ export default { for (const group of markerGroups.values()) { for (let i = 0; i < group.length - 1; i += 2) { const startMarker = group[i]; - reportWhitespace({ - checkIndex: startMarker.endIndex, - highlightStartIndex: startMarker.startIndex, - highlightEndIndex: startMarker.endIndex + 2, - }); + reportWhitespace( + startMarker.endIndex, + startMarker.startIndex, + startMarker.endIndex + 2, + ); const endMarker = group[i + 1]; - reportWhitespace({ - checkIndex: endMarker.startIndex - 1, - highlightStartIndex: endMarker.startIndex - 2, - highlightEndIndex: endMarker.endIndex, - }); + reportWhitespace( + endMarker.startIndex - 1, + endMarker.startIndex - 2, + endMarker.endIndex, + ); } } From ea7c2f0e33edf61cab47e660596712ba284f1ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 22:51:45 +0900 Subject: [PATCH 04/10] wip: simplify --- src/rules/no-space-in-emphasis.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index 1ef17d10..ba36ae41 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -13,7 +13,7 @@ * @typedef {"spaceInEmphasis"} NoSpaceInEmphasisMessageIds * @typedef {[{ checkStrikethrough?: boolean }]} NoSpaceInEmphasisOptions * @typedef {MarkdownRuleDefinition<{ RuleOptions: NoSpaceInEmphasisOptions, MessageIds: NoSpaceInEmphasisMessageIds }>} NoSpaceInEmphasisRuleDefinition - * @typedef {{marker: string, startIndex: number, endIndex: number}} EmphasisMarker + * @typedef {{startIndex: number, endIndex: number}} EmphasisMarker */ //----------------------------------------------------------------------------- @@ -136,8 +136,6 @@ export default { /** @type {Heading | Paragraph | TableCell} */ node, ) { const maskedText = bufferState.buffer.join(""); - /** @type {EmphasisMarker[]} */ - const markers = []; /** @type {Map} */ const markerGroups = new Map(); @@ -145,21 +143,14 @@ export default { let match; while ((match = markerPattern.exec(maskedText)) !== null) { + const marker = match.groups.marker; const startIndex = match.index + node.position.start.offset; const endIndex = startIndex + match.groups.marker.length; - markers.push({ - marker: match.groups.marker, - startIndex, - endIndex, - }); - } - - for (const marker of markers) { - if (!markerGroups.has(marker.marker)) { - markerGroups.set(marker.marker, []); + if (!markerGroups.has(marker)) { + markerGroups.set(marker, []); } - markerGroups.get(marker.marker).push(marker); + markerGroups.get(marker).push({ startIndex, endIndex }); } for (const group of markerGroups.values()) { From 27e81ace2130b4afbf4fa1858c6056faaec3aa71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 23:11:11 +0900 Subject: [PATCH 05/10] wip: simplify --- src/rules/no-space-in-emphasis.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index ba36ae41..16cb348b 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -8,12 +8,12 @@ //----------------------------------------------------------------------------- /** + * @import { SourceRange } from "@eslint/core"; * @import { Heading, Paragraph, TableCell, Text } from "mdast"; * @import { MarkdownRuleDefinition } from "../types.js"; * @typedef {"spaceInEmphasis"} NoSpaceInEmphasisMessageIds * @typedef {[{ checkStrikethrough?: boolean }]} NoSpaceInEmphasisOptions * @typedef {MarkdownRuleDefinition<{ RuleOptions: NoSpaceInEmphasisOptions, MessageIds: NoSpaceInEmphasisMessageIds }>} NoSpaceInEmphasisRuleDefinition - * @typedef {{startIndex: number, endIndex: number}} EmphasisMarker */ //----------------------------------------------------------------------------- @@ -29,8 +29,8 @@ const whitespacePattern = /[ \t]/u; */ function createMarkerPattern(checkStrikethrough) { return checkStrikethrough - ? /(?<=(?\*\*\*|\*\*|\*|___|__|_|~~|~)/gu - : /(?<=(?\*\*\*|\*\*|\*|___|__|_)/gu; + ? /(?<=(?\*\*\*|\*\*|\*|___|__|_|~~|~)/dgu + : /(?<=(?\*\*\*|\*\*|\*|___|__|_)/dgu; } //----------------------------------------------------------------------------- @@ -136,7 +136,7 @@ export default { /** @type {Heading | Paragraph | TableCell} */ node, ) { const maskedText = bufferState.buffer.join(""); - /** @type {Map} */ + /** @type {Map} */ const markerGroups = new Map(); /** @type {RegExpExecArray | null} */ @@ -144,29 +144,31 @@ export default { while ((match = markerPattern.exec(maskedText)) !== null) { const marker = match.groups.marker; - const startIndex = match.index + node.position.start.offset; - const endIndex = startIndex + match.groups.marker.length; + const [startOffset, endOffset] = + match.indices.groups.marker.map( + index => index + node.position.start.offset, + ); if (!markerGroups.has(marker)) { markerGroups.set(marker, []); } - markerGroups.get(marker).push({ startIndex, endIndex }); + markerGroups.get(marker).push([startOffset, endOffset]); } for (const group of markerGroups.values()) { for (let i = 0; i < group.length - 1; i += 2) { const startMarker = group[i]; reportWhitespace( - startMarker.endIndex, - startMarker.startIndex, - startMarker.endIndex + 2, + startMarker[1], + startMarker[0], + startMarker[1] + 2, ); const endMarker = group[i + 1]; reportWhitespace( - endMarker.startIndex - 1, - endMarker.startIndex - 2, - endMarker.endIndex, + endMarker[0] - 1, + endMarker[0] - 2, + endMarker[1], ); } } From 2396ced9df172e293a498393be6e2cebf0041018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 23:30:06 +0900 Subject: [PATCH 06/10] wip: simplify --- src/rules/no-space-in-emphasis.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index 16cb348b..a4454915 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -78,8 +78,8 @@ export default { const [{ checkStrikethrough }] = context.options; const markerPattern = createMarkerPattern(checkStrikethrough); - /** @type {{ buffer: string[], startOffset: number } | null} */ - let bufferState = null; + /** @type {string[] | null} */ + let buffer = null; /** * Reports a surrounding-space violation if present. @@ -113,10 +113,7 @@ export default { /** @type {Heading | Paragraph | TableCell} */ node, ) { const [startOffset, endOffset] = sourceCode.getRange(node); - bufferState = { - buffer: new Array(endOffset - startOffset).fill(" "), - startOffset, - }; + buffer = new Array(endOffset - startOffset).fill(" "); }, // Add the content of a `Text` node into the current buffer at the correct offsets. @@ -124,10 +121,11 @@ export default { /** @type {Text} */ node, ) { const start = - node.position.start.offset - bufferState.startOffset; + node.position.start.offset - + sourceCode.getParent(node).position.start.offset; const text = sourceCode.getText(node); for (let i = 0; i < text.length; i++) { - bufferState.buffer[start + i] = text[i]; + buffer[start + i] = text[i]; } }, @@ -135,7 +133,7 @@ export default { ":matches(heading, paragraph, tableCell):exit"( /** @type {Heading | Paragraph | TableCell} */ node, ) { - const maskedText = bufferState.buffer.join(""); + const maskedText = buffer.join(""); /** @type {Map} */ const markerGroups = new Map(); @@ -144,7 +142,7 @@ export default { while ((match = markerPattern.exec(maskedText)) !== null) { const marker = match.groups.marker; - const [startOffset, endOffset] = + const [startOffset, endOffset] = // Adjust `markerPattern` match indices to the full source code. match.indices.groups.marker.map( index => index + node.position.start.offset, ); @@ -173,7 +171,7 @@ export default { } } - bufferState = null; + buffer = null; }, }; }, From 5d3b62e025f42d04f49f1370da645ed25e554b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 23:45:12 +0900 Subject: [PATCH 07/10] wip --- src/rules/no-space-in-emphasis.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index a4454915..bf56f2b9 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -108,28 +108,28 @@ export default { } return { - // Initialize `bufferState` with a whitespace-masked character buffer for the node. "heading, paragraph, tableCell"( /** @type {Heading | Paragraph | TableCell} */ node, ) { const [startOffset, endOffset] = sourceCode.getRange(node); + + // Initialize `buffer` with a whitespace-masked character array. buffer = new Array(endOffset - startOffset).fill(" "); }, - // Add the content of a `Text` node into the current buffer at the correct offsets. ":matches(heading, paragraph, tableCell) > text"( /** @type {Text} */ node, ) { - const start = - node.position.start.offset - - sourceCode.getParent(node).position.start.offset; - const text = sourceCode.getText(node); - for (let i = 0; i < text.length; i++) { - buffer[start + i] = text[i]; + const [startOffset, endOffset] = sourceCode.getRange(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 - sourceCode.getParent(node).position.start.offset // Adjust to parent node (`Heading`, `Paragraph`, `TableCell`) start. + ] = sourceCode.text[i]; } }, - // Join the character buffer into a masked string, run checks, then clear state. ":matches(heading, paragraph, tableCell):exit"( /** @type {Heading | Paragraph | TableCell} */ node, ) { From f74fcc8ecd5fc655b9ce51302cd7086dc99115b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sat, 4 Oct 2025 23:59:25 +0900 Subject: [PATCH 08/10] wip: simplify --- src/rules/no-space-in-emphasis.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index bf56f2b9..8db27bea 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -78,8 +78,8 @@ export default { const [{ checkStrikethrough }] = context.options; const markerPattern = createMarkerPattern(checkStrikethrough); - /** @type {string[] | null} */ - let buffer = null; + /** @type {string[]} */ + let buffer; /** * Reports a surrounding-space violation if present. @@ -170,8 +170,6 @@ export default { ); } } - - buffer = null; }, }; }, From 24b0b7e6b0435575b6f92bdb193678bb03ef8f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Sun, 5 Oct 2025 22:37:49 +0900 Subject: [PATCH 09/10] wip --- src/rules/no-space-in-emphasis.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index 8db27bea..b5c7e1e3 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -29,8 +29,8 @@ const whitespacePattern = /[ \t]/u; */ function createMarkerPattern(checkStrikethrough) { return checkStrikethrough - ? /(?<=(?\*\*\*|\*\*|\*|___|__|_|~~|~)/dgu - : /(?<=(?\*\*\*|\*\*|\*|___|__|_)/dgu; + ? /(?<=(? index + node.position.start.offset, - ); + 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, []); From f70c88a809a9b2c61ef754d9948b28f5eb1a4fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Tue, 7 Oct 2025 15:59:26 +0900 Subject: [PATCH 10/10] wip --- src/rules/no-space-in-emphasis.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rules/no-space-in-emphasis.js b/src/rules/no-space-in-emphasis.js index b5c7e1e3..cdf32a94 100644 --- a/src/rules/no-space-in-emphasis.js +++ b/src/rules/no-space-in-emphasis.js @@ -121,12 +121,12 @@ export default { /** @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; // Add the content of a `Text` node into the current buffer at the correct offsets. for (let i = startOffset; i < endOffset; i++) { - buffer[ - i - sourceCode.getParent(node).position.start.offset // Adjust to parent node (`Heading`, `Paragraph`, `TableCell`) start. - ] = sourceCode.text[i]; + buffer[i - parentNodeStartOffset] = sourceCode.text[i]; } },