Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions scripts/ci/mdlint.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,40 @@ def explain():
)


class BacktickLinkError(Error):
CODE = "E004"

def __init__(self, span: Span):
super().__init__(type(self).CODE, "link contains backtick", span)

@staticmethod
def explain():
return textwrap.dedent(
"""
URLs in links wrapping text should not contain backticks (`).

Example:
```
[Some link](`https://github.com/rerun-io/rerun`)
```

Our markdown renderer will treat the above link as a _relative path_
instead of a URL. If the above markdown is in `examples/robotics/README.md`,
it will link to \"https://rerun.io/examples/robotics/`https://github.com/rerun-io/rerun`\".

Solution: Remove the backticks.
```
[Some link](https://github.com/rerun-io/rerun)
```
"""
)


EXPLAIN = {
NoClosingTagError.CODE: NoClosingTagError.explain,
NoPrecedingBlankLineError.CODE: NoPrecedingBlankLineError.explain,
BlankLinesError.CODE: BlankLinesError.explain,
BacktickLinkError.CODE: BacktickLinkError.explain,
}


Expand Down Expand Up @@ -314,12 +344,37 @@ def check_video_elements(content: str, errors: list[Error]) -> None:
search_start = spans.element.end + 1


def check_invalid_links(content: str, errors: list[Error]) -> None:
search_start = 0
while True:
mid_point = content.find("](`", search_start)
if mid_point == -1:
return

link_start = content.rfind("[", 0, mid_point)
if link_start == -1:
# TODO(jprochazk): invalid link
search_start = mid_point
continue

link_end = content.find(")", mid_point)
if link_end == -1:
# TODO(jprochazk): invalid link
search_start = mid_point
continue

search_start = link_end + 1

errors.append(BacktickLinkError(span=Span(link_start, link_end)))


def check_file(path: str) -> str | None:
errors: list[Error] = []
content = Path(path).read_text()

check_picture_elements(content, errors)
check_video_elements(content, errors)
check_invalid_links(content, errors)

if len(errors) != 0:
return "\n".join([error.render(path, content) for error in errors])
Expand Down