Skip to content

馃悰 Bug: sentence boundaries next to inline links, images, and emphasis go undetected聽#1364

Description

@deemp

AI disclosure: This issue was composed by OpenCode using the Space Bunny model

  • I have tried restarting my IDE and the issue persists.
  • I have pulled the latest main branch of the repository.
  • I have searched for related issues and found none that matched my issue.

Expected

Both prettier-plugin-sentences-per-line and sentences-per-line/one should notice a sentence boundary that falls immediately before or after an inline structure, because there are two sentences on one source line:

First sentence ends here. [The link](#x) starts the next.

should be formatted as:

First sentence ends here.
[The link](#x) starts the next.

Actual

Neither package notices. The line is left alone by the formatter and reported clean by the lint rule.

Additional Info

Versions: prettier-plugin-sentences-per-line@0.2.5, eslint-plugin-sentences-per-line@0.1.6, prettier@3.9.9, eslint@10.11.0, Node v25.9.0. Verified against the published tarballs, not local builds.

import markdown from "@eslint/markdown";
import { Linter } from "eslint";
import sentencesPerLine from "eslint-plugin-sentences-per-line";
import * as prettier from "prettier";
import * as prettierPlugin from "prettier-plugin-sentences-per-line";

const linter = new Linter();
const config = [
	{
		files: ["**/*.md"],
		language: "markdown/gfm",
		plugins: { markdown, "sentences-per-line": sentencesPerLine },
		rules: { "sentences-per-line/one": "error" },
	},
];

const inputs = [
	"First sentence ends here. [The link](#x) starts the next.\n",
	"Bold end here. **Bold end.** Next sentence follows.\n",
	"One sentence. ![alt](img.png) Two sentence.\n",
	"Passes here. `npm test` Fails hard.\n",
];

for (const input of inputs) {
	const formatted = await prettier.format(input, {
		parser: "markdown",
		plugins: [prettierPlugin],
	});

	console.log("input:   ", JSON.stringify(input));
	console.log("prettier:", JSON.stringify(formatted));
	console.log(
		"eslint:  ",
		JSON.stringify(
			linter
				.verify(input, config, "test.md")
				.map((message) => `${message.line}:${message.column}`),
		),
	);
	console.log();
}

All four inputs come back unchanged from the formatter and with no lint reports.

I see the same root cause in both packages, which is why I am filing this against the repository rather than one package.

For the prettier plugin, modifyNodeIfMultipleSentencesInLine scans the word children of a single sentence node for a word ending in ., !, or ? followed by whitespace and a capital letter. Prettier's Markdown preprocess turns each text run into its own sentence node, so an inline link, image, emphasis, or code span becomes a sibling of the sentence nodes rather than a child. A boundary that lands on that seam has no single sentence node containing both halves of the pattern, so it cannot be found by that scan.

For the lint rule, getIndexBeforeSecondSentence is called per text child of a paragraph, so the same seam hides the boundary there. The same blind spot should apply to markdownlint-sentences-per-line, which calls the same helper on each raw source line: isCapitalizedAlphabetCharacter sees the [ of the link and declines.

A fix would need the paragraph's raw source with the ranges spanned by inline structures masked out, then re-segmentation to locate the boundary. That logic belongs in the core sentences-per-line package next to getSentenceStartIndices so all three consumers benefit from it. Happy to send a pull request with tests if this is welcome; I would want to start with a small change confined to the boundary detection.

馃挅

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions