From 0f82967e634d1aafbba21cf3d5bd3b67bc7b73cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Mon, 27 Oct 2025 00:01:12 +0900 Subject: [PATCH 01/10] feat(eslint-plugin-mark): create `no-consecutive-black-line` rule --- .../eslint-plugin-mark/src/rules/index.js | 2 + .../src/rules/no-consecutive-blank-line.js | 120 +++++++++++++++ .../rules/no-consecutive-blank-line.test.js | 1 + .../docs/rules/no-consecutive-blank-line.md | 137 ++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js create mode 100644 packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js create mode 100644 website/docs/rules/no-consecutive-blank-line.md diff --git a/packages/eslint-plugin-mark/src/rules/index.js b/packages/eslint-plugin-mark/src/rules/index.js index 75047b75..256b4d65 100644 --- a/packages/eslint-plugin-mark/src/rules/index.js +++ b/packages/eslint-plugin-mark/src/rules/index.js @@ -11,6 +11,7 @@ import enCapitalization from './en-capitalization.js'; import headingId from './heading-id.js'; import imageTitle from './image-title.js'; import noBoldParagraph from './no-bold-paragraph.js'; +import noConsecutiveBlankLine from './no-consecutive-blank-line.js'; import noControlCharacter from './no-control-character.js'; import noCurlyQuote from './no-curly-quote.js'; import noDoubleSpace from './no-double-space.js'; @@ -32,6 +33,7 @@ export default { 'heading-id': headingId, 'image-title': imageTitle, 'no-bold-paragraph': noBoldParagraph, + 'no-consecutive-blank-line': noConsecutiveBlankLine, 'no-control-character': noControlCharacter, 'no-curly-quote': noCurlyQuote, 'no-double-space': noDoubleSpace, diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js new file mode 100644 index 00000000..dbc9b390 --- /dev/null +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -0,0 +1,120 @@ +// TODO + +/** + * @fileoverview Rule to enforce consistent emphasis style. + * @author 루밀LuMir(lumirlumir) + */ + +// -------------------------------------------------------------------------------- +// Import +// -------------------------------------------------------------------------------- + +import { URL_RULE_DOCS } from '../core/constants.js'; + +// -------------------------------------------------------------------------------- +// Typedef +// -------------------------------------------------------------------------------- + +/** + * @import { RuleModule } from '../core/types.js'; + * @typedef {[{ style: 'consistent' | '*' | '_' }]} RuleOptions + * @typedef {'style'} MessageIds + */ + +// -------------------------------------------------------------------------------- +// Rule Definition +// -------------------------------------------------------------------------------- + +/** @type {RuleModule} */ +export default { + meta: { + type: 'layout', + + docs: { + description: 'Enforce consistent emphasis style', + url: URL_RULE_DOCS('consistent-emphasis-style'), + recommended: false, + stylistic: true, + }, + + fixable: 'code', + + schema: [ + { + type: 'object', + properties: { + style: { + enum: ['consistent', '*', '_'], + }, + }, + additionalProperties: false, + }, + ], + + defaultOptions: [ + { + style: 'consistent', + }, + ], + + messages: { + style: 'Emphasis style should be `{{ style }}`.', + }, + + language: 'markdown', + + dialects: ['commonmark', 'gfm'], + }, + + create(context) { + const { sourceCode } = context; + const [{ style }] = context.options; + + /** @type {string | null} */ + let emphasisStyle = style === 'consistent' ? null : style; + + /** + * @param {number} startOffset + * @param {number} endOffset + */ + function reportStyle(startOffset, endOffset) { + const stringifiedEmphasisStyle = String(emphasisStyle); + + context.report({ + loc: { + start: sourceCode.getLocFromIndex(startOffset), + end: sourceCode.getLocFromIndex(endOffset), + }, + + messageId: 'style', + + data: { + style: stringifiedEmphasisStyle, + }, + + fix(fixer) { + return fixer.replaceTextRange( + [startOffset, endOffset], + stringifiedEmphasisStyle, + ); + }, + }); + } + + return { + emphasis(node) { + const [nodeStartOffset, nodeEndOffset] = sourceCode.getRange(node); + const currentEmphasisStyle = sourceCode.text[nodeStartOffset]; + + if (emphasisStyle === null) { + emphasisStyle = currentEmphasisStyle; + } + + if (emphasisStyle !== currentEmphasisStyle) { + reportStyle(nodeStartOffset, nodeStartOffset + 1); + reportStyle(nodeEndOffset - 1, nodeEndOffset); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js new file mode 100644 index 00000000..70b786d1 --- /dev/null +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js @@ -0,0 +1 @@ +// TODO diff --git a/website/docs/rules/no-consecutive-blank-line.md b/website/docs/rules/no-consecutive-blank-line.md new file mode 100644 index 00000000..926610b3 --- /dev/null +++ b/website/docs/rules/no-consecutive-blank-line.md @@ -0,0 +1,137 @@ + +
+ +## Rule Details + +This rule enforces a single, consistent style for emphasis (italic text) in Markdown files. Consistent formatting makes it easier to understand a document, and mixing different emphasis styles can reduce readability. + +An emphasis is defined as text wrapped in either `*` (asterisks) or `_` (underscores). While Markdown allows any of these styles, this rule ensures that only one is used throughout the document. + +## Examples + +### :x: Incorrect {#incorrect} + +Examples of **incorrect** code for this rule: + +#### Default + +```md eslint-check + + +*foo* +_bar_ +*baz* +**_foo_** +__*bar*__ +_**foo**_ +*__bar__* +___foo___ +***bar*** +``` + +```md eslint-check + + +_foo_ +*bar* +_baz_ +__*foo*__ +**_bar_** +*__foo__* +_**bar**_ +***foo*** +___bar___ +``` + +#### With `{ style: '*' }` Option + +```md eslint-check + + +_foo_ +**_bar_** +_**baz**_ +___qux___ +``` + +#### With `{ style: '_' }` Option + +```md eslint-check + + +*foo* +__*bar*__ +*__baz__* +***qux*** +``` + +### :white_check_mark: Correct {#correct} + +Examples of **correct** code for this rule: + +#### Default + +```md eslint-check + + +*foo* +__*bar*__ +*__baz__* +***qux*** +``` + +```md eslint-check + + +_foo_ +**_bar_** +_**baz**_ +___qux___ +``` + +#### With `{ style: '*' }` Option + +```md eslint-check + + +*foo* +__*bar*__ +*__baz__* +***qux*** +``` + +#### With `{ style: '_' }` Option + +```md eslint-check + + +_foo_ +**_bar_** +_**baz**_ +___qux___ +``` + +## Options + +```js +'mark/consistent-emphasis-style': ['error', { + style: 'consistent', +}] +``` + +### `style` + +> Type: `'consistent' | '*' | '_'` / Default: `'consistent'` + +When `style` is set to `'consistent'`, the rule enforces that all emphasis in the document use the same style as the first one encountered. + +You can also specify a particular style by setting style to `'*'` or `'_'`, which will enforce that all emphasis use the specified style. + +## Fix + +This rule fixes the emphasis by replacing them with the configured style. + +## Prior Art + +- [`MD012` - Multiple consecutive blank lines](https://github.com/DavidAnson/markdownlint/blob/main/doc/md012.md#md012---multiple-consecutive-blank-lines) +- [`remark-lint-no-consecutive-blank-lines`](https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-consecutive-blank-lines#remark-lint-no-consecutive-blank-lines) From 480972724e34ba439dd273f2c8b01b16024285cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Mon, 27 Oct 2025 00:11:08 +0900 Subject: [PATCH 02/10] wip --- eslint.config.mjs | 1 + website/docs/rules/no-consecutive-blank-line.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/eslint.config.mjs b/eslint.config.mjs index ccae3177..9cf76db5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -27,6 +27,7 @@ export default defineConfig([ 'Fix', 'Limitations', 'When Not To Use It', + 'Further Reading', 'Prior Art', ], }, diff --git a/website/docs/rules/no-consecutive-blank-line.md b/website/docs/rules/no-consecutive-blank-line.md index 926610b3..e89be664 100644 --- a/website/docs/rules/no-consecutive-blank-line.md +++ b/website/docs/rules/no-consecutive-blank-line.md @@ -131,6 +131,10 @@ You can also specify a particular style by setting style to `'*'` or `'_'`, whic This rule fixes the emphasis by replacing them with the configured style. +## Further Reading + +- [CommonMark Spec: Blank Line](https://spec.commonmark.org/0.31.2/#blank-line) + ## Prior Art - [`MD012` - Multiple consecutive blank lines](https://github.com/DavidAnson/markdownlint/blob/main/doc/md012.md#md012---multiple-consecutive-blank-lines) From c17d2b994972dd420e04e24d567f1bb1980a70e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Mon, 27 Oct 2025 00:21:18 +0900 Subject: [PATCH 03/10] wip --- .../eslint-plugin-mark/src/rules/no-consecutive-blank-line.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index dbc9b390..1b06b4fd 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -1,7 +1,5 @@ -// TODO - /** - * @fileoverview Rule to enforce consistent emphasis style. + * @fileoverview Rule to disallow consecutive blank lines. * @author 루밀LuMir(lumirlumir) */ From 18d8691e88c6b4989bad9a1c128696391f4ae0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Thu, 20 Nov 2025 14:31:13 +0900 Subject: [PATCH 04/10] wip --- .../src/rules/no-consecutive-blank-line.js | 74 +++++-------------- 1 file changed, 18 insertions(+), 56 deletions(-) diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index 1b06b4fd..fabbab11 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -15,8 +15,8 @@ import { URL_RULE_DOCS } from '../core/constants.js'; /** * @import { RuleModule } from '../core/types.js'; - * @typedef {[{ style: 'consistent' | '*' | '_' }]} RuleOptions - * @typedef {'style'} MessageIds + * @typedef {[{ max: number, skipCode: boolean }]} RuleOptions + * @typedef {'noConsecutiveBlankLine'} MessageIds */ // -------------------------------------------------------------------------------- @@ -29,20 +29,24 @@ export default { type: 'layout', docs: { - description: 'Enforce consistent emphasis style', - url: URL_RULE_DOCS('consistent-emphasis-style'), + description: 'Disallow consecutive blank lines', + url: URL_RULE_DOCS('no-consecutive-blank-line'), recommended: false, stylistic: true, }, - fixable: 'code', + fixable: 'whitespace', schema: [ { type: 'object', properties: { - style: { - enum: ['consistent', '*', '_'], + max: { + type: 'integer', + minimum: 0, + }, + skipCode: { + type: 'boolean', }, }, additionalProperties: false, @@ -51,12 +55,13 @@ export default { defaultOptions: [ { - style: 'consistent', + max: 1, + skipCode: true, }, ], messages: { - style: 'Emphasis style should be `{{ style }}`.', + noConsecutiveBlankLine: 'Consecutive blank lines are not allowed.', }, language: 'markdown', @@ -64,55 +69,12 @@ export default { dialects: ['commonmark', 'gfm'], }, - create(context) { - const { sourceCode } = context; - const [{ style }] = context.options; - - /** @type {string | null} */ - let emphasisStyle = style === 'consistent' ? null : style; - - /** - * @param {number} startOffset - * @param {number} endOffset - */ - function reportStyle(startOffset, endOffset) { - const stringifiedEmphasisStyle = String(emphasisStyle); - - context.report({ - loc: { - start: sourceCode.getLocFromIndex(startOffset), - end: sourceCode.getLocFromIndex(endOffset), - }, - - messageId: 'style', - - data: { - style: stringifiedEmphasisStyle, - }, - - fix(fixer) { - return fixer.replaceTextRange( - [startOffset, endOffset], - stringifiedEmphasisStyle, - ); - }, - }); - } + create(/* context */) { + // const { sourceCode } = context; + // const [{ max, skipCode }] = context.options; return { - emphasis(node) { - const [nodeStartOffset, nodeEndOffset] = sourceCode.getRange(node); - const currentEmphasisStyle = sourceCode.text[nodeStartOffset]; - - if (emphasisStyle === null) { - emphasisStyle = currentEmphasisStyle; - } - - if (emphasisStyle !== currentEmphasisStyle) { - reportStyle(nodeStartOffset, nodeStartOffset + 1); - reportStyle(nodeEndOffset - 1, nodeEndOffset); - } - }, + 'root:exit'(/* node */) {}, }; }, }; From 1d08498d9c45c2a43377ec67bc0899bf63f89813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Thu, 20 Nov 2025 16:08:39 +0900 Subject: [PATCH 05/10] wip --- .../eslint-plugin-mark/src/core/ast/index.js | 3 +- .../src/core/ast/is-blank-line.js | 29 +++++++++++++++ .../src/core/ast/is-blank-line.test.js | 1 + .../src/rules/no-consecutive-blank-line.js | 37 +++++++++++++++++-- .../rules/no-consecutive-blank-line.test.js | 35 +++++++++++++++++- 5 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 packages/eslint-plugin-mark/src/core/ast/is-blank-line.js create mode 100644 packages/eslint-plugin-mark/src/core/ast/is-blank-line.test.js diff --git a/packages/eslint-plugin-mark/src/core/ast/index.js b/packages/eslint-plugin-mark/src/core/ast/index.js index 99423f5b..3b2504fb 100644 --- a/packages/eslint-plugin-mark/src/core/ast/index.js +++ b/packages/eslint-plugin-mark/src/core/ast/index.js @@ -1,4 +1,5 @@ import getElementsByTagName from './html.js'; +import isBlankLine from './is-blank-line.js'; import SkipRanges from './skip-ranges.js'; -export { getElementsByTagName, SkipRanges }; +export { getElementsByTagName, isBlankLine, SkipRanges }; diff --git a/packages/eslint-plugin-mark/src/core/ast/is-blank-line.js b/packages/eslint-plugin-mark/src/core/ast/is-blank-line.js new file mode 100644 index 00000000..4b8ebfbc --- /dev/null +++ b/packages/eslint-plugin-mark/src/core/ast/is-blank-line.js @@ -0,0 +1,29 @@ +/** + * @fileoverview Check if a line is blank. + * @see https://spec.commonmark.org/0.31.2/#blank-line + */ + +// -------------------------------------------------------------------------------- +// Helper +// -------------------------------------------------------------------------------- + +const whitespaceChars = new Set([' ', '\t']); + +// -------------------------------------------------------------------------------- +// Export +// -------------------------------------------------------------------------------- + +/** + * Check if a line is blank. + * @param {string} str Line string. + * @returns {boolean} `true` if the line is blank. `false` otherwise. + */ +export default function isBlankLine(str) { + for (let i = 0; i < str.length; i++) { + if (!whitespaceChars.has(str[i])) { + return false; + } + } + + return true; +} diff --git a/packages/eslint-plugin-mark/src/core/ast/is-blank-line.test.js b/packages/eslint-plugin-mark/src/core/ast/is-blank-line.test.js new file mode 100644 index 00000000..70b786d1 --- /dev/null +++ b/packages/eslint-plugin-mark/src/core/ast/is-blank-line.test.js @@ -0,0 +1 @@ +// TODO diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index fabbab11..85f9ebae 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -7,6 +7,7 @@ // Import // -------------------------------------------------------------------------------- +import { isBlankLine } from '../core/ast/index.js'; import { URL_RULE_DOCS } from '../core/constants.js'; // -------------------------------------------------------------------------------- @@ -69,12 +70,40 @@ export default { dialects: ['commonmark', 'gfm'], }, - create(/* context */) { - // const { sourceCode } = context; - // const [{ max, skipCode }] = context.options; + create(context) { + const { + sourceCode: { lines }, + } = context; + const [{ max /* skipCode */ }] = context.options; return { - 'root:exit'(/* node */) {}, + 'root:exit'() { + /** @type {number | null} */ + let startIdx = null; + + for (let currentIdx = 0; currentIdx < lines.length; currentIdx++) { + if (isBlankLine(lines[currentIdx])) { + if (startIdx === null) { + startIdx = currentIdx; + } + } else if (startIdx !== null) { + if (currentIdx - startIdx > max) { + context.report({ + loc: { + start: { line: startIdx + 1, column: 0 }, + end: { + line: currentIdx, + column: lines[currentIdx - 1].length, + }, + }, + messageId: 'noConsecutiveBlankLine', + }); + } + + startIdx = null; + } + } + }, }; }, }; diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js index 70b786d1..635eb5b6 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js @@ -1 +1,34 @@ -// TODO +/** + * @fileoverview Test for `no-consecutive-blank-line.js`. + * @author 루밀LuMir(lumirlumir) + */ + +// -------------------------------------------------------------------------------- +// Import +// -------------------------------------------------------------------------------- + +import { getFileName, ruleTester } from '../core/tests/index.js'; +import rule from './no-consecutive-blank-line.js'; + +// -------------------------------------------------------------------------------- +// Test +// -------------------------------------------------------------------------------- + +ruleTester(getFileName(import.meta.url), rule, { + valid: [ + { + name: 'Empty', + code: '', + }, + { + name: 'Empty string', + code: ' ', + }, + { + name: 'CR LF CRLF - 1', + code: '123\r456\n789\r\n123', + }, + ], + + invalid: [], +}); From f2b048add9e21b1b168d07f46127d1f41cb2a480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Thu, 20 Nov 2025 16:32:16 +0900 Subject: [PATCH 06/10] wip --- .../src/rules/no-consecutive-blank-line.js | 8 ++++---- .../src/rules/no-consecutive-blank-line.test.js | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index 85f9ebae..9fd4916b 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -44,7 +44,7 @@ export default { properties: { max: { type: 'integer', - minimum: 0, + minimum: 0, // TODO: Think about proper minimum value }, skipCode: { type: 'boolean', @@ -90,10 +90,10 @@ export default { if (currentIdx - startIdx > max) { context.report({ loc: { - start: { line: startIdx + 1, column: 0 }, + start: { line: startIdx + 1, column: 1 }, end: { - line: currentIdx, - column: lines[currentIdx - 1].length, + line: currentIdx + 1, + column: 1, }, }, messageId: 'noConsecutiveBlankLine', diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js index 635eb5b6..fd0f4b1b 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.test.js @@ -24,10 +24,6 @@ ruleTester(getFileName(import.meta.url), rule, { name: 'Empty string', code: ' ', }, - { - name: 'CR LF CRLF - 1', - code: '123\r456\n789\r\n123', - }, ], invalid: [], From 62775653195549657af1dd7ea955419ccab769e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Thu, 20 Nov 2025 17:55:20 +0900 Subject: [PATCH 07/10] wip --- .../src/rules/no-consecutive-blank-line.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index 9fd4916b..42fe1c71 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -81,8 +81,12 @@ export default { /** @type {number | null} */ let startIdx = null; - for (let currentIdx = 0; currentIdx < lines.length; currentIdx++) { - if (isBlankLine(lines[currentIdx])) { + /* + * We use `currentIdx <= lines.length` instead of `currentIdx < lines.length` + * to handle the case where the file ends with blank lines. + */ + for (let currentIdx = 0; currentIdx <= lines.length; currentIdx++) { + if (lines[currentIdx] !== undefined && isBlankLine(lines[currentIdx])) { if (startIdx === null) { startIdx = currentIdx; } @@ -90,7 +94,7 @@ export default { if (currentIdx - startIdx > max) { context.report({ loc: { - start: { line: startIdx + 1, column: 1 }, + start: { line: startIdx + max + 1, column: 1 }, end: { line: currentIdx + 1, column: 1, From 8be66614f27ddec5fe9ff61bc0268d7b9fbd9b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Thu, 20 Nov 2025 18:11:26 +0900 Subject: [PATCH 08/10] wip --- .../src/rules/no-consecutive-blank-line.js | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index 42fe1c71..53373341 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -81,12 +81,8 @@ export default { /** @type {number | null} */ let startIdx = null; - /* - * We use `currentIdx <= lines.length` instead of `currentIdx < lines.length` - * to handle the case where the file ends with blank lines. - */ - for (let currentIdx = 0; currentIdx <= lines.length; currentIdx++) { - if (lines[currentIdx] !== undefined && isBlankLine(lines[currentIdx])) { + for (let currentIdx = 0; currentIdx < lines.length; currentIdx++) { + if (isBlankLine(lines[currentIdx])) { if (startIdx === null) { startIdx = currentIdx; } @@ -107,6 +103,19 @@ export default { startIdx = null; } } + + if (startIdx !== null && lines.length - startIdx > max) { + context.report({ + loc: { + start: { line: startIdx + max + 1, column: 1 }, + end: { + line: lines.length + 1, + column: 1, + }, + }, + messageId: 'noConsecutiveBlankLine', + }); + } }, }; }, From 3244ebf8cae2b05597a61e8df3733806d43e6f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Thu, 20 Nov 2025 18:11:51 +0900 Subject: [PATCH 09/10] wip --- .../eslint-plugin-mark/src/rules/no-consecutive-blank-line.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index 53373341..f8477bd7 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -104,6 +104,7 @@ export default { } } + // Handle the case where the file ends with blank lines. if (startIdx !== null && lines.length - startIdx > max) { context.report({ loc: { From dbb90b2e8044450841ab2a7aed75e419b2d3d61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Thu, 20 Nov 2025 18:55:55 +0900 Subject: [PATCH 10/10] wip --- .../src/rules/no-consecutive-blank-line.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js index f8477bd7..d8af9818 100644 --- a/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js +++ b/packages/eslint-plugin-mark/src/rules/no-consecutive-blank-line.js @@ -104,7 +104,10 @@ export default { } } - // Handle the case where the file ends with blank lines. + /* + * Handle the case where the file ends with blank lines. + * Now, `currentIdx` is equal to `lines.length`. + */ if (startIdx !== null && lines.length - startIdx > max) { context.report({ loc: {