AI disclosure: This issue was composed by OpenCode using the Space Bunny model
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.  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.
馃挅
AI disclosure: This issue was composed by OpenCode using the Space Bunny model
mainbranch of the repository.Expected
Both
prettier-plugin-sentences-per-lineandsentences-per-line/oneshould notice a sentence boundary that falls immediately before or after an inline structure, because there are two sentences on one source line:should be formatted as:
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.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,
modifyNodeIfMultipleSentencesInLinescans thewordchildren of a singlesentencenode for awordending in.,!, or?followed by whitespace and a capital letter. Prettier's Markdownpreprocessturns eachtextrun into its ownsentencenode, 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,
getIndexBeforeSecondSentenceis called pertextchild of a paragraph, so the same seam hides the boundary there. The same blind spot should apply tomarkdownlint-sentences-per-line, which calls the same helper on each raw source line:isCapitalizedAlphabetCharactersees 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-linepackage next togetSentenceStartIndicesso 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.馃挅