diff --git a/scripts/prose_lint.py b/scripts/prose_lint.py index 97b26121..31867bb7 100644 --- a/scripts/prose_lint.py +++ b/scripts/prose_lint.py @@ -383,11 +383,19 @@ def extracted_comments(path: Path, lines: list[str]) -> list[tuple[int, str, boo closing = '' if end >= 0 else closing continue masked = strip_strings(line, spec['quotes']) + # A line comment runs to end of line, so a block opener after one is text. + # Left unbounded it opens a block that swallows the code lines below. + # A documentation comment bounds it too, being exempt from linting rather than from here. + line_at = len(line) + for marker in spec['line']: + at = masked.find(marker) + if 0 <= at < line_at: + line_at = at cut = len(line) leading = True for opener, closer in spec['block']: at = masked.find(opener) - if 0 <= at < cut: + if 0 <= at < min(cut, line_at): if any(line[at:].startswith(d) for d in spec['doc']): continue cut, leading = at, not line[:at].strip() diff --git a/scripts/test_prose_lint.py b/scripts/test_prose_lint.py index 46288291..0384ad9d 100644 --- a/scripts/test_prose_lint.py +++ b/scripts/test_prose_lint.py @@ -368,6 +368,18 @@ def test_a_comment_inside_a_fenced_block_is_skipped(self) -> None: self.assertEqual(['comment-wrap'], self.flag('a.md', 'Prose.\n\n\n')) + def test_a_block_opener_inside_a_line_comment_is_text(self) -> None: + """Read as a real opener it opens a block, and the code lines below are linted as prose. + + The documentation form is the same case: exempting it from linting must not leave the + ceiling unbounded, or the syntax whose doc marker is a line comment reopens the defect. + """ + for name, text in (('a.cs', '// Match a /* opener here\nvar x = 1; // Two things. Here.\n'), + ('a.cs', '/// See a /* opener here\nvar x = 1; // Two things. Here.\n'), + ('a.ps1', '# Match a <# opener here\n$x = 1 # Two things. Here.\n')): + with self.subTest(file=name, line=text.split('\n')[0]): + self.assertEqual(['comment-wrap'], self.flag(name, text)) + def test_css_has_block_comments_only(self) -> None: """A `//` in CSS is the scheme separator of a URL, not a comment marker.""" self.assertEqual([], self.flag('a.css', 'a { background: url(http://x/y. Z); }\n'))