From cd87222b1b67ef8ea5abe1ca2c7f5c23fb33e820 Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 16:29:12 +0800 Subject: [PATCH 1/9] Add extension for hallmark link reference order Signed-off-by: Callan Gray --- mdformat_hallmark/__init__.py | 10 +++ mdformat_hallmark/hallmark_links_extension.py | 66 +++++++++++++++++++ mdformat_plugin/__init__.py | 5 -- mdformat_plugin/plugin.py | 24 ------- pyproject.toml | 9 ++- tests/fixtures.md | 64 ++++++++++++++++++ tests/test_fixtures.py | 4 +- 7 files changed, 148 insertions(+), 34 deletions(-) create mode 100644 mdformat_hallmark/__init__.py create mode 100644 mdformat_hallmark/hallmark_links_extension.py delete mode 100644 mdformat_plugin/__init__.py delete mode 100644 mdformat_plugin/plugin.py diff --git a/mdformat_hallmark/__init__.py b/mdformat_hallmark/__init__.py new file mode 100644 index 0000000..fa3efe6 --- /dev/null +++ b/mdformat_hallmark/__init__.py @@ -0,0 +1,10 @@ +"""An mdformat plugin for compatibility with hallmark formatted Markdown and Common-Changelog.""" + +__version__ = "0.0.1" + +from .hallmark_links_extension import HallmarkLinksExtension + + +__all__ = [ + "HallmarkLinksExtension" +] \ No newline at end of file diff --git a/mdformat_hallmark/hallmark_links_extension.py b/mdformat_hallmark/hallmark_links_extension.py new file mode 100644 index 0000000..c2db882 --- /dev/null +++ b/mdformat_hallmark/hallmark_links_extension.py @@ -0,0 +1,66 @@ +from markdown_it import MarkdownIt +from mdformat.renderer import RenderTreeNode, RenderContext +from mdformat.plugins import ParserExtensionInterface +from markdown_it.token import Token +import re + + +class HallmarkLinksExtension(ParserExtensionInterface): + """ + mdformat plugin extension to format references used by versions and + renders sorted by semantic-version order. + """ + @staticmethod + def update_mdit(mdit: MarkdownIt) -> None: + # save original parser + original_parse = mdit.parse + + def new_parse(src: str, env=None): + if env is None: + env = {} + + # regex for `[label]: href "title"` + pattern = re.compile( + r'^\[([^\]]+)\]:\s*(\S+)(?:\s+"([^"]+)")?$', + re.MULTILINE, + ) + + # collect defs + matches = pattern.findall(src) + refs = { + label: {"href": href, "title": title} + for label, href, title in matches + } + + # remove them from the source + src = pattern.sub("", src).rstrip() + + # call original parse on the cleaned text + tokens = original_parse(src, env) + + # append a dummy hallmark_refs token at the end + if refs: + token = Token("hallmark_refs", "", 0) + token.meta = {"refs": refs} + tokens.append(token) + + return tokens + + # patch parser + mdit.parse = new_parse + + @staticmethod + def _render_hallmark_refs(node: RenderTreeNode, ctx: RenderContext) -> str: + """Render collected reference defs in hallmark ordered format.""" + refs: dict[str, dict[str, str]] = node.meta["refs"] + out = [] + sorted_ref_items = reversed(list(refs.items())) + for label, ref in sorted_ref_items: + line = f"[{label}]: {ref['href']}" + if ref.get("title"): + line += f' "{ref["title"]}"' + out.append(line) + return "\n".join(out) + "\n" + + RENDERERS = {"hallmark_refs": _render_hallmark_refs} + CHANGES_AST = True diff --git a/mdformat_plugin/__init__.py b/mdformat_plugin/__init__.py deleted file mode 100644 index 1c98271..0000000 --- a/mdformat_plugin/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""An mdformat plugin for...""" - -__version__ = "0.0.1" - -from .plugin import RENDERERS, update_mdit # noqa: F401 diff --git a/mdformat_plugin/plugin.py b/mdformat_plugin/plugin.py deleted file mode 100644 index 8fff61c..0000000 --- a/mdformat_plugin/plugin.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Mapping - -from markdown_it import MarkdownIt -from mdformat.renderer import RenderContext, RenderTreeNode -from mdformat.renderer.typing import Render - - -def update_mdit(mdit: MarkdownIt) -> None: - """Update the parser, e.g. by adding a plugin: `mdit.use(myplugin)`""" - pass - - -def _render_table(node: RenderTreeNode, context: RenderContext) -> str: - """Render a `RenderTreeNode` of type "table". - - Change "table" to the name of the syntax you want to render. - """ - return "" - - -# A mapping from syntax tree node type to a function that renders it. -# This can be used to overwrite renderer functions of existing syntax -# or add support for new syntax. -RENDERERS: Mapping[str, Render] = {"table": _render_table} diff --git a/pyproject.toml b/pyproject.toml index d728245..093ede7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["flit_core >=3.2.0,<4"] build-backend = "flit_core.buildapi" [project] -name = "mdformat_plugin" +name = "mdformat-hallmark" authors = [ { name = "Chris Sewell", email = "executablebooks@gmail.com" }, ] @@ -33,7 +33,7 @@ dev = ["pre-commit"] Homepage = "https://github.com/executablebooks/mdformat-plugin" [project.entry-points."mdformat.parser_extension"] -plugin = "mdformat_plugin" +"hallmark" = "mdformat_hallmark:HallmarkLinksExtension" [tool.flit.sdist] include = [] @@ -46,7 +46,10 @@ force_sort_within_sections = true no_lines_before = ["LOCALFOLDER"] # Configure isort to work without access to site-packages -known_first_party = ["mdformat_plugin", "tests"] +known_first_party = ["mdformat_hallmark", "tests"] # Settings for Black compatibility profile = "black" + +[tool.pytest.ini_options] +log_cli = true \ No newline at end of file diff --git a/tests/fixtures.md b/tests/fixtures.md index 31d6be2..768e2a9 100644 --- a/tests/fixtures.md +++ b/tests/fixtures.md @@ -22,3 +22,67 @@ Some *markdown* * c . + +table test +. +| Month | Savings | +| -------- | ------- | +| January | $250 | +| February | $80 | +| March | $420 | +. +| Month | Savings | +| -------- | ------- | +| January | $250 | +| February | $80 | +| March | $420 | +. + +real test +. +# Changelog + +add your syntax here + +## [5.4.0] - 2025-04-14 + +- asd +- sda + +## [5.3.2] - 2025-03-31 + +## [5.3.1] - 2025-02-17 + +## [5.3.0] - 2025-02-05 + +## [5.2.1] - 2025-01-10 + +[5.2.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.2.1 +[5.3.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.0 +[5.3.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.1 +[5.3.2]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.2 +[5.4.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.4.0 +. +# Changelog + +add your syntax here + +## [5.4.0] - 2025-04-14 + +- asd +- sda + +## [5.3.2] - 2025-03-31 + +## [5.3.1] - 2025-02-17 + +## [5.3.0] - 2025-02-05 + +## [5.2.1] - 2025-01-10 + +[5.4.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.4.0 +[5.3.2]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.2 +[5.3.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.1 +[5.3.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.0 +[5.2.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.2.1 +. \ No newline at end of file diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 68fc3bf..c805a5a 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -12,6 +12,6 @@ "line,title,text,expected", fixtures, ids=[f[1] for f in fixtures] ) def test_fixtures(line, title, text, expected): - output = mdformat.text(text, extensions={"plugin"}) - print(output) + output = mdformat.text(text, extensions={"hallmark"}) + # output = mdformat.text(text, codeformatters={"python"}) assert output.rstrip() == expected.rstrip(), output From 6e4b26fc4eb2617efb612bab0da74a582774368c Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 16:29:29 +0800 Subject: [PATCH 2/9] Packaging changes Signed-off-by: Callan Gray --- .github/workflows/tests.yml | 2 +- LICENSE | 2 +- README.md | 33 ++++++++++----------------------- mdformat_hallmark/__init__.py | 4 ++-- pyproject.toml | 4 ++-- tox.ini | 2 +- 6 files changed, 17 insertions(+), 30 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9706ae0..cc62d8b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: - name: Run pytest run: | - pytest --cov=mdformat_plugin --cov-report=xml --cov-report=term-missing + pytest --cov=mdformat_hallmark --cov-report=xml --cov-report=term-missing - name: Upload to Codecov if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.7 diff --git a/LICENSE b/LICENSE index 2a08e1c..292a6fc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Executable Books +Copyright (c) 2025 Executable Books Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 41054b9..f3ae713 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,10 @@ -# mdformat-plugin +# mdformat-hallmark -[![Build Status][ci-badge]][ci-link] -[![codecov.io][cov-badge]][cov-link] -[![PyPI version][pypi-badge]][pypi-link] +[![Build Status](https://github.com/calgray/mdformat-hallmark/actions/workflows/tests.yml/badge.svg?branch=master)]() +[![codecov.io](https://codecov.io/gh/calgray/mdformat-hallmark/branch/main/graph/badge.svg)](https://codecov.io/gh/xarray-contrib/astropy-xarray) +[![PyPI version](https://badge.fury.io/py/mdformat-hallmark.svg)]() -An [mdformat](https://github.com/executablebooks/mdformat) plugin for... - -## Required changes for a new plugin - -This demonstration is setup with a plugin named `plugin`. -There are a number of locations to change. -At a top level for a plugin `foo` at least the following changes are required - -- Global find and replace `mdformat_plugin` to `mdformat_foo` including folder names. -- Global find and replace `mdformat-plugin` to `mdformat-foo` including folder names. -- `tests/test_fixtures.py`: `output = mdformat.text(text, extensions={"plugin"})` becomes `output = mdformat.text(text, extensions={"foo"})` -- `pyproject.toml` in addition to the global find and replace: `plugin = "mdformat_plugin"` becomes `foo = "mdformat_foo"` - -Do not forget to update authorship / maintainers in `pyproject.toml` as well. +An [mdformat](https://github.com/executablebooks/mdformat) plugin for compatibility with [hallmark](https://github.com/vweevers/hallmark) formatted Markdown and [Common Changelog](https://common-changelog.org/). ## Development @@ -75,9 +62,9 @@ or trigger the GitHub Action job, by creating a release with a tag equal to the Note, this requires generating an API key on PyPi and adding it to the repository `Settings/Secrets`, under the name `PYPI_KEY`. -[ci-badge]: https://github.com/executablebooks/mdformat-plugin/workflows/CI/badge.svg?branch=master +[ci-badge]: https://github.com/executablebooks/mdformat-hallmark/workflows/CI/badge.svg?branch=master [ci-link]: https://github.com/executablebooks/mdformat/actions?query=workflow%3ACI+branch%3Amaster+event%3Apush -[cov-badge]: https://codecov.io/gh/executablebooks/mdformat-plugin/branch/master/graph/badge.svg -[cov-link]: https://codecov.io/gh/executablebooks/mdformat-plugin -[pypi-badge]: https://img.shields.io/pypi/v/mdformat-plugin.svg -[pypi-link]: https://pypi.org/project/mdformat-plugin +[cov-badge]: https://codecov.io/gh/executablebooks/mdformat-hallmark/branch/master/graph/badge.svg +[cov-link]: https://codecov.io/gh/executablebooks/mdformat-hallmark +[pypi-badge]: https://img.shields.io/pypi/v/mdformat-hallmark.svg +[pypi-link]: https://pypi.org/project/mdformat-hallmark diff --git a/mdformat_hallmark/__init__.py b/mdformat_hallmark/__init__.py index fa3efe6..dd89089 100644 --- a/mdformat_hallmark/__init__.py +++ b/mdformat_hallmark/__init__.py @@ -1,4 +1,4 @@ -"""An mdformat plugin for compatibility with hallmark formatted Markdown and Common-Changelog.""" +"""An mdformat plugin for compatibility with hallmark formatted Markdown and Common Changelog.""" __version__ = "0.0.1" @@ -7,4 +7,4 @@ __all__ = [ "HallmarkLinksExtension" -] \ No newline at end of file +] diff --git a/pyproject.toml b/pyproject.toml index 093ede7..59e2fce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "flit_core.buildapi" [project] name = "mdformat-hallmark" authors = [ - { name = "Chris Sewell", email = "executablebooks@gmail.com" }, + { name = "Callan Gray", email = "cal.j.gray@gmail.com" }, ] readme = "README.md" classifiers = [ @@ -30,7 +30,7 @@ test = [ dev = ["pre-commit"] [project.urls] -Homepage = "https://github.com/executablebooks/mdformat-plugin" +Homepage = "https://github.com/calgray/mdformat-hallmark" [project.entry-points."mdformat.parser_extension"] "hallmark" = "mdformat_hallmark:HallmarkLinksExtension" diff --git a/tox.ini b/tox.ini index c284ba3..4ad3108 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ commands = pytest {posargs} [testenv:py{36,37,38,39}-cov] extras = test -commands = pytest --cov={envsitepackagesdir}/mdformat_plugin {posargs} +commands = pytest --cov={envsitepackagesdir}/mdformat_hallmark {posargs} [testenv:py{36,37,38,39}-pre-commit] extras = dev From 750703c44296e510c2b782152907cd8693b2b376 Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 16:26:22 +0800 Subject: [PATCH 3/9] Fix pre-commit jobs --- .github/workflows/tests.yml | 8 +++--- .pre-commit-config.yaml | 18 ++++++------- mdformat_hallmark/__init__.py | 10 +++---- mdformat_hallmark/hallmark_links_extension.py | 27 +++++++++---------- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cc62d8b..d206fb5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,9 +13,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v5 with: python-version: 3.7 - uses: pre-commit/action@v2.0.0 @@ -28,10 +28,10 @@ jobs: os: [ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e481775..7418a8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v5.0.0 hooks: - id: end-of-file-fixer - id: mixed-line-ending @@ -8,22 +8,22 @@ repos: - id: check-yaml - id: check-toml - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.8.0 + rev: v1.10.0 hooks: - id: python-check-blanket-noqa - repo: https://github.com/timothycrosley/isort - rev: 5.8.0 + rev: 5.13.2 hooks: - id: isort - repo: https://github.com/psf/black - rev: 20.8b1 + rev: 24.10.0 hooks: - id: black -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.0 +- repo: https://github.com/pycqa/flake8 + rev: 7.3.0 hooks: - id: flake8 additional_dependencies: - - flake8-bugbear==21.3.2 - - flake8-builtins==1.5.3 - - flake8-comprehensions==3.4.0 + - flake8-bugbear + - flake8-builtins + - flake8-comprehensions diff --git a/mdformat_hallmark/__init__.py b/mdformat_hallmark/__init__.py index dd89089..809d488 100644 --- a/mdformat_hallmark/__init__.py +++ b/mdformat_hallmark/__init__.py @@ -1,10 +1,10 @@ -"""An mdformat plugin for compatibility with hallmark formatted Markdown and Common Changelog.""" +""" +An mdformat plugin for compatibility with hallmark formatted Markdown +and Common Changelog. +""" __version__ = "0.0.1" from .hallmark_links_extension import HallmarkLinksExtension - -__all__ = [ - "HallmarkLinksExtension" -] +__all__ = ["HallmarkLinksExtension"] diff --git a/mdformat_hallmark/hallmark_links_extension.py b/mdformat_hallmark/hallmark_links_extension.py index c2db882..9af62a7 100644 --- a/mdformat_hallmark/hallmark_links_extension.py +++ b/mdformat_hallmark/hallmark_links_extension.py @@ -1,18 +1,20 @@ +import re + from markdown_it import MarkdownIt -from mdformat.renderer import RenderTreeNode, RenderContext -from mdformat.plugins import ParserExtensionInterface from markdown_it.token import Token -import re +from mdformat.plugins import ParserExtensionInterface +from mdformat.renderer import RenderContext, RenderTreeNode class HallmarkLinksExtension(ParserExtensionInterface): """ - mdformat plugin extension to format references used by versions and + mdformat plugin extension to format references used by versions and renders sorted by semantic-version order. """ + @staticmethod def update_mdit(mdit: MarkdownIt) -> None: - # save original parser + """Patch the default parser to render references in semver order.""" original_parse = mdit.parse def new_parse(src: str, env=None): @@ -20,25 +22,22 @@ def new_parse(src: str, env=None): env = {} # regex for `[label]: href "title"` - pattern = re.compile( + references_re = re.compile( r'^\[([^\]]+)\]:\s*(\S+)(?:\s+"([^"]+)")?$', re.MULTILINE, ) - - # collect defs - matches = pattern.findall(src) + matches = references_re.findall(src) refs = { - label: {"href": href, "title": title} - for label, href, title in matches + label: {"href": href, "title": title} for label, href, title in matches } - # remove them from the source - src = pattern.sub("", src).rstrip() + # remove references from the source + src = references_re.sub("", src).rstrip() # call original parse on the cleaned text tokens = original_parse(src, env) - # append a dummy hallmark_refs token at the end + # append a hallmark_refs token at the end if refs: token = Token("hallmark_refs", "", 0) token.meta = {"refs": refs} From b088ce094d7a25636fe3997b6817bf3e4e770ddd Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 16:35:41 +0800 Subject: [PATCH 4/9] Fix Github actions Signed-off-by: Callan Gray --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d206fb5..ff0b95b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,7 +24,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.9, 3.10, 3.11, 3.12, 3.13] os: [ubuntu-latest, windows-latest] steps: From a082da7c10535f5adc3a1e475e1e5bbd60205704 Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 18:14:38 +0800 Subject: [PATCH 5/9] Handle edge cases, use packaging.version sorting Signed-off-by: Callan Gray --- .github/workflows/tests.yml | 2 +- mdformat_hallmark/hallmark_links_extension.py | 72 ++++++-- pyproject.toml | 3 +- tests/fixtures.md | 156 ++++++++++++------ 4 files changed, 165 insertions(+), 68 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ff0b95b..e7eb12e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,7 +24,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.9, 3.10, 3.11, 3.12, 3.13] + python-version: ['3.10', '3.11', '3.12', '3.13'] os: [ubuntu-latest, windows-latest] steps: diff --git a/mdformat_hallmark/hallmark_links_extension.py b/mdformat_hallmark/hallmark_links_extension.py index 9af62a7..8f35c51 100644 --- a/mdformat_hallmark/hallmark_links_extension.py +++ b/mdformat_hallmark/hallmark_links_extension.py @@ -1,9 +1,57 @@ +from dataclasses import dataclass import re from markdown_it import MarkdownIt from markdown_it.token import Token from mdformat.plugins import ParserExtensionInterface from mdformat.renderer import RenderContext, RenderTreeNode +from packaging.version import InvalidVersion, Version + +_REFERENCES_RE = re.compile( + r'^\[([^\]]+)\]:\s*(\S+)(?:\s+"([^"]+)")?$', + re.MULTILINE, +) # regex for `[label]: href "title"` + + +@dataclass +class SemverReference: + semver: Version + label: str + href: str + title: str | None + + def __str__(self): + line = f"[{self.label}]: {self.href}" + if self.title: + line += f' "{self.title}"' + return line + + +def _extract_semver_references(src: str) -> tuple[list[SemverReference], str]: + refs: list[SemverReference] = [] + remove_spans: list[tuple[int, int]] = [] + + for m in _REFERENCES_RE.finditer(src): + label, href, title = m.groups() + try: + semver = Version(label) + except InvalidVersion: + continue # skip non-semver labels + refs.append(SemverReference(semver, label, href, title)) + remove_spans.append(m.span()) + + # remove references from the source + out_src = src + for start, end in reversed(remove_spans): + out_src = out_src[:start] + out_src[end:] + + # Normalize whitespace + out_src = re.sub(r"\n{3,}", "\n\n", out_src).rstrip() + + # sort semver references + refs.sort(key=lambda ref: ref.semver, reverse=True) + + return refs, out_src class HallmarkLinksExtension(ParserExtensionInterface): @@ -15,27 +63,24 @@ class HallmarkLinksExtension(ParserExtensionInterface): @staticmethod def update_mdit(mdit: MarkdownIt) -> None: """Patch the default parser to render references in semver order.""" + original_parse = mdit.parse def new_parse(src: str, env=None): if env is None: env = {} + if not src.lstrip().startswith("# Changelog"): + return original_parse(src, env) - # regex for `[label]: href "title"` - references_re = re.compile( - r'^\[([^\]]+)\]:\s*(\S+)(?:\s+"([^"]+)")?$', - re.MULTILINE, - ) - matches = references_re.findall(src) + # extract semver references and remove from src + matches, out_src = _extract_semver_references(src) refs = { - label: {"href": href, "title": title} for label, href, title in matches + match.label: {"href": match.href, "title": match.title} + for match in matches } - # remove references from the source - src = references_re.sub("", src).rstrip() - # call original parse on the cleaned text - tokens = original_parse(src, env) + tokens = original_parse(out_src, env) # append a hallmark_refs token at the end if refs: @@ -53,13 +98,12 @@ def _render_hallmark_refs(node: RenderTreeNode, ctx: RenderContext) -> str: """Render collected reference defs in hallmark ordered format.""" refs: dict[str, dict[str, str]] = node.meta["refs"] out = [] - sorted_ref_items = reversed(list(refs.items())) - for label, ref in sorted_ref_items: + for label, ref in refs.items(): line = f"[{label}]: {ref['href']}" if ref.get("title"): line += f' "{ref["title"]}"' out.append(line) - return "\n".join(out) + "\n" + return "\n".join(out) RENDERERS = {"hallmark_refs": _render_hallmark_refs} CHANGES_AST = True diff --git a/pyproject.toml b/pyproject.toml index 59e2fce..a66eeb6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ keywords = ["mdformat", "markdown", "markdown-it"] requires-python = ">=3.7" dependencies = [ "mdformat >=0.7.0,<0.8.0", + "packaging >= 23.0", ] dynamic = ["version", "description"] @@ -52,4 +53,4 @@ known_first_party = ["mdformat_hallmark", "tests"] profile = "black" [tool.pytest.ini_options] -log_cli = true \ No newline at end of file +log_cli = true diff --git a/tests/fixtures.md b/tests/fixtures.md index 768e2a9..c44d6b2 100644 --- a/tests/fixtures.md +++ b/tests/fixtures.md @@ -1,88 +1,140 @@ -a test +not changelog test . This is the input Markdown test, then below add the expected output. + +- a [reference][] +- b [0.0.1] +* c [1.0.0] + +[unused reference]: https://example.com +[0.0.1]: https://example.com +[reference]: https://example.com +[1.0.0]: https://example.com . This is the input Markdown test, then below add the expected output. -. -another test +- a [reference] +- b [0.0.1] + +* c [1.0.0] + +[0.0.1]: https://example.com +[1.0.0]: https://example.com +[reference]: https://example.com . -Some *markdown* -- a -- b -* c +correct changelog test . -Some *markdown* +# Changelog -- a -- b +## [10.1.0] - 2025-01-01 -* c -. +## [2.10.0] - 2025-01-01 -table test -. -| Month | Savings | -| -------- | ------- | -| January | $250 | -| February | $80 | -| March | $420 | +## [2.0.0] - 2025-01-01 + +## [1.0.10] - 2025-01-01 + +## [1.0.0] - 2025-01-01 + +## [0.0.10] - 2025-01-01 + +## [0.0.2] - 2025-01-01 + +## [0.0.1] - 2025-01-01 + +[10.1.0]: https://example.com +[2.10.0]: https://example.com +[2.0.0]: https://example.com +[1.0.10]: https://example.com +[1.0.0]: https://example.com +[0.0.10]: https://example.com +[0.0.2]: https://example.com +[0.0.1]: https://example.com . -| Month | Savings | -| -------- | ------- | -| January | $250 | -| February | $80 | -| March | $420 | +# Changelog + +## [10.1.0] - 2025-01-01 + +## [2.10.0] - 2025-01-01 + +## [2.0.0] - 2025-01-01 + +## [1.0.10] - 2025-01-01 + +## [1.0.0] - 2025-01-01 + +## [0.0.10] - 2025-01-01 + +## [0.0.2] - 2025-01-01 + +## [0.0.1] - 2025-01-01 + +[10.1.0]: https://example.com +[2.10.0]: https://example.com +[2.0.0]: https://example.com +[1.0.10]: https://example.com +[1.0.0]: https://example.com +[0.0.10]: https://example.com +[0.0.2]: https://example.com +[0.0.1]: https://example.com . -real test +unsorted changelog test . # Changelog -add your syntax here +## [10.1.0] - 2025-01-01 -## [5.4.0] - 2025-04-14 +## [2.0.0] - 2025-01-01 -- asd -- sda +## [2.10.0] - 2025-01-01 -## [5.3.2] - 2025-03-31 +## [1.0.10] - 2025-01-01 -## [5.3.1] - 2025-02-17 +## [1.0.0] - 2025-01-01 -## [5.3.0] - 2025-02-05 +## [0.0.10] - 2025-01-01 -## [5.2.1] - 2025-01-10 +## [0.0.2] - 2025-01-01 -[5.2.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.2.1 -[5.3.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.0 -[5.3.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.1 -[5.3.2]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.2 -[5.4.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.4.0 +## [0.0.1] - 2025-01-01 + +[0.0.1]: https://example.com +[0.0.2]: https://example.com +[0.0.10]: https://example.com +[1.0.0]: https://example.com +[1.0.10]: https://example.com +[2.0.0]: https://example.com +[2.10.0]: https://example.com +[10.1.0]: https://example.com . # Changelog -add your syntax here +## [10.1.0] - 2025-01-01 + +## [2.0.0] - 2025-01-01 -## [5.4.0] - 2025-04-14 +## [2.10.0] - 2025-01-01 -- asd -- sda +## [1.0.10] - 2025-01-01 -## [5.3.2] - 2025-03-31 +## [1.0.0] - 2025-01-01 -## [5.3.1] - 2025-02-17 +## [0.0.10] - 2025-01-01 -## [5.3.0] - 2025-02-05 +## [0.0.2] - 2025-01-01 -## [5.2.1] - 2025-01-10 +## [0.0.1] - 2025-01-01 -[5.4.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.4.0 -[5.3.2]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.2 -[5.3.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.1 -[5.3.0]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.3.0 -[5.2.1]: https://gitlab.com/ska-telescope/sdp/ska-sdp-lmc-queue-connector/-/releases/5.2.1 -. \ No newline at end of file +[10.1.0]: https://example.com +[2.10.0]: https://example.com +[2.0.0]: https://example.com +[1.0.10]: https://example.com +[1.0.0]: https://example.com +[0.0.10]: https://example.com +[0.0.2]: https://example.com +[0.0.1]: https://example.com +. From de14999e4491973ace2b603d3dce3bfea12b067a Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 18:51:25 +0800 Subject: [PATCH 6/9] Require blank lines Signed-off-by: Callan Gray --- mdformat_hallmark/hallmark_links_extension.py | 2 +- tests/fixtures.md | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mdformat_hallmark/hallmark_links_extension.py b/mdformat_hallmark/hallmark_links_extension.py index 8f35c51..b7cdeaf 100644 --- a/mdformat_hallmark/hallmark_links_extension.py +++ b/mdformat_hallmark/hallmark_links_extension.py @@ -103,7 +103,7 @@ def _render_hallmark_refs(node: RenderTreeNode, ctx: RenderContext) -> str: if ref.get("title"): line += f' "{ref["title"]}"' out.append(line) - return "\n".join(out) + return "\n\n".join(out) RENDERERS = {"hallmark_refs": _render_hallmark_refs} CHANGES_AST = True diff --git a/tests/fixtures.md b/tests/fixtures.md index c44d6b2..a1cd460 100644 --- a/tests/fixtures.md +++ b/tests/fixtures.md @@ -46,12 +46,19 @@ correct changelog test ## [0.0.1] - 2025-01-01 [10.1.0]: https://example.com + [2.10.0]: https://example.com + [2.0.0]: https://example.com + [1.0.10]: https://example.com + [1.0.0]: https://example.com + [0.0.10]: https://example.com + [0.0.2]: https://example.com + [0.0.1]: https://example.com . # Changelog @@ -73,12 +80,19 @@ correct changelog test ## [0.0.1] - 2025-01-01 [10.1.0]: https://example.com + [2.10.0]: https://example.com + [2.0.0]: https://example.com + [1.0.10]: https://example.com + [1.0.0]: https://example.com + [0.0.10]: https://example.com + [0.0.2]: https://example.com + [0.0.1]: https://example.com . @@ -130,11 +144,18 @@ unsorted changelog test ## [0.0.1] - 2025-01-01 [10.1.0]: https://example.com + [2.10.0]: https://example.com + [2.0.0]: https://example.com + [1.0.10]: https://example.com + [1.0.0]: https://example.com + [0.0.10]: https://example.com + [0.0.2]: https://example.com + [0.0.1]: https://example.com . From 0e3eb9b3dd22806e22059de4a4f642b10fd6a392 Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 18:57:44 +0800 Subject: [PATCH 7/9] Set min Python to 3.10 Signed-off-by: Callan Gray --- .github/workflows/tests.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e7eb12e..83f4a84 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: '3.10' - uses: pre-commit/action@v2.0.0 tests: @@ -47,11 +47,12 @@ jobs: pytest --cov=mdformat_hallmark --cov-report=xml --cov-report=term-missing - name: Upload to Codecov - if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.7 - uses: codecov/codecov-action@v1 + if: matrix.os == 'ubuntu-latest' && matrix.python-version == 3.10 + uses: codecov/codecov-action@v5.4.2 with: - name: pytests-py3.7 - flags: pytests + name: codecov-umbrella + flags: unit + env_vars: RUNNER_OS,PYTHON_VERSION file: ./coverage.xml fail_ci_if_error: true @@ -61,9 +62,9 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: '3.10' - name: Installation (deps and package) run: | @@ -82,10 +83,10 @@ jobs: steps: - name: Checkout source uses: actions/checkout@v2 - - name: Set up Python 3.7 - uses: actions/setup-python@v1 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: '3.10' - name: install flit run: | pip install flit~=3.0 From 131a79ce74c9f2cd241601ccb1b5546e1f451993 Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 23:07:13 +0800 Subject: [PATCH 8/9] Setup codecov Signed-off-by: Callan Gray --- .github/workflows/tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 83f4a84..f39ef29 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,6 +19,8 @@ jobs: with: python-version: '3.10' - uses: pre-commit/action@v2.0.0 + with: + fail_ci_if_error: false tests: runs-on: ${{ matrix.os }} @@ -54,7 +56,7 @@ jobs: flags: unit env_vars: RUNNER_OS,PYTHON_VERSION file: ./coverage.xml - fail_ci_if_error: true + fail_ci_if_error: false pre-commit-hook: runs-on: ubuntu-latest From 2fa3593dc2f653b7d423bc5bd86c4d45aa5c1214 Mon Sep 17 00:00:00 2001 From: Callan Gray Date: Fri, 22 Aug 2025 23:21:56 +0800 Subject: [PATCH 9/9] CI related fixes --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f39ef29..d1aabd8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,9 +18,8 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.10' - - uses: pre-commit/action@v2.0.0 - with: - fail_ci_if_error: false + - uses: pre-commit/action@v3.0.1 + continue-on-error: true tests: runs-on: ${{ matrix.os }} @@ -56,6 +55,7 @@ jobs: flags: unit env_vars: RUNNER_OS,PYTHON_VERSION file: ./coverage.xml + token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: false pre-commit-hook: