From e37f5483e8ad054c8f10244841fb617024b6805d Mon Sep 17 00:00:00 2001 From: Jared Dillard Date: Sun, 22 Mar 2026 15:55:35 -0700 Subject: [PATCH] Fix double extension in llms.txt URLs when source suffix matches sourcelink suffix --- CHANGELOG.rst | 6 ++++++ sphinx_llms_txt/__init__.py | 2 +- sphinx_llms_txt/writer.py | 8 ++++++- tests/test_uri_template.py | 42 +++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 83059ae..552ae99 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,12 @@ Changelog ========= +0.7.2 +----- + +- Fix double extension in llms.txt URLs when source suffix matches sourcelink suffix + `#63 `_ + 0.7.1 ----- diff --git a/sphinx_llms_txt/__init__.py b/sphinx_llms_txt/__init__.py index c64762b..def4ad5 100644 --- a/sphinx_llms_txt/__init__.py +++ b/sphinx_llms_txt/__init__.py @@ -21,7 +21,7 @@ from .manager import LLMSFullManager from .processor import DocumentProcessor from .writer import FileWriter -__version__ = "0.7.1" +__version__ = "0.7.2" # Export classes needed by tests __all__ = [ diff --git a/sphinx_llms_txt/writer.py b/sphinx_llms_txt/writer.py index 44b9279..9a3ef2a 100644 --- a/sphinx_llms_txt/writer.py +++ b/sphinx_llms_txt/writer.py @@ -163,11 +163,17 @@ class FileWriter: title = page_titles.get(docname, docname) + # Avoid duplicate extensions when suffix matches + # sourcelink_suffix (e.g., both are ".txt") + effective_sourcelink_suffix = sourcelink_suffix + if suffix and suffix == sourcelink_suffix: + effective_sourcelink_suffix = "" + uri = uri_template.format( base_url=base_url, docname=docname, suffix=suffix or "", - sourcelink_suffix=sourcelink_suffix, + sourcelink_suffix=effective_sourcelink_suffix, ) f.write(f"- [{title}]({uri})\n") diff --git a/tests/test_uri_template.py b/tests/test_uri_template.py index f5ad243..c6773cd 100644 --- a/tests/test_uri_template.py +++ b/tests/test_uri_template.py @@ -132,6 +132,48 @@ def test_uri_template_custom(tmp_path): assert "- [Home Page](https://example.com/raw/index.rst)" in content +def test_uri_template_no_double_extension_when_suffix_matches_sourcelink(tmp_path): + """Test that .txt suffix + .txt sourcelink_suffix doesn't produce .txt.txt URLs.""" + build_dir = tmp_path / "build" + build_dir.mkdir() + + sources_dir = build_dir / "_sources" + sources_dir.mkdir() + + class MockApp: + class Config: + html_sourcelink_suffix = ".txt" + + config = Config() + + config = { + "llms_txt_file": True, + "llms_txt_filename": "llms.txt", + "html_baseurl": "https://example.com", + } + writer = FileWriter(config, str(build_dir), MockApp()) + + page_titles = { + "index": "Home Page", + "contents": "Table of Contents", + } + + # .txt source files — suffix matches sourcelink_suffix + page_order = [("index", ".txt"), ("contents", ".txt")] + + writer.write_verbose_info_to_file(page_order, page_titles, 0, sources_dir) + + verbose_file = build_dir / "llms.txt" + with open(verbose_file, "r", encoding="utf-8") as f: + content = f.read() + + # Should NOT have double .txt.txt extension + assert ".txt.txt" not in content + # Should have single .txt extension + assert "- [Home Page](https://example.com/_sources/index.txt)" in content + assert "- [Table of Contents](https://example.com/_sources/contents.txt)" in content + + def test_uri_template_invalid_fallback(tmp_path): """ Test that invalid template falls back to default sources template when