Skip to content

Commit 282e493

Browse files
committed
Docs(fix[assets]): Drop stale tabs script
why: gp-sphinx removes tabs.js after rendering, leaving pages with a missing asset reference even though inline tabs operate through CSS. what: - Filter only tabs.js from Sphinx page contexts at late priority - Verify final tab markup and assets with a one-page Sphinx build
1 parent d91f79b commit 282e493

2 files changed

Lines changed: 133 additions & 0 deletions

File tree

docs/conf.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
import pathlib
66
import sys
7+
import typing as t
78

89
from gp_sphinx.config import make_linkcode_resolve, merge_sphinx_config
10+
from sphinx.application import Sphinx
911

1012
import libtmux
1113

@@ -60,4 +62,65 @@
6062
exclude_patterns=["_build", "AGENTS.md", "CLAUDE.md", "superpowers/**"],
6163
)
6264
conf["myst_enable_extensions"].append("fieldlist")
65+
66+
_shared_setup = t.cast("t.Callable[[Sphinx], None]", conf["setup"])
67+
68+
69+
def _omit_removed_inline_tabs_script(
70+
app: Sphinx,
71+
_pagename: str,
72+
_templatename: str,
73+
context: dict[str, t.Any],
74+
_doctree: object | None,
75+
) -> None:
76+
"""Keep rendered pages consistent with gp-sphinx's static assets.
77+
78+
gp-sphinx removes ``tabs.js`` after a successful HTML build because
79+
sphinx-inline-tabs needs only its CSS behavior here. Remove the matching
80+
page-context entry before Sphinx renders a stale ``script`` reference.
81+
82+
Parameters
83+
----------
84+
app : sphinx.application.Sphinx
85+
Active Sphinx application.
86+
_pagename : str
87+
Name of the page being rendered.
88+
_templatename : str
89+
Template used to render the page.
90+
context : dict[str, Any]
91+
Template context containing Sphinx's script assets.
92+
_doctree : object | None
93+
Page doctree, when available.
94+
"""
95+
if "sphinx_inline_tabs" not in app.extensions:
96+
return
97+
98+
script_files = context.get("script_files")
99+
if not isinstance(script_files, list):
100+
return
101+
102+
context["script_files"] = [
103+
asset
104+
for asset in script_files
105+
if getattr(asset, "filename", None) != "_static/tabs.js"
106+
]
107+
108+
109+
def setup(app: Sphinx) -> None:
110+
"""Configure shared gp-sphinx hooks and project asset consistency.
111+
112+
Parameters
113+
----------
114+
app : sphinx.application.Sphinx
115+
Active Sphinx application.
116+
"""
117+
_shared_setup(app)
118+
app.connect(
119+
"html-page-context",
120+
_omit_removed_inline_tabs_script,
121+
priority=900,
122+
)
123+
124+
125+
conf["setup"] = setup
63126
globals().update(conf)

tests/docs/test_static_assets.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Contracts for documentation assets emitted into HTML pages."""
2+
3+
from __future__ import annotations
4+
5+
import pathlib
6+
import textwrap
7+
8+
from sphinx.testing.util import SphinxTestApp
9+
10+
_ROOT = pathlib.Path(__file__).parents[2]
11+
12+
13+
def test_docs_setup_omits_deleted_inline_tabs_script_from_html(
14+
tmp_path: pathlib.Path,
15+
) -> None:
16+
"""Rendered tabs work without referencing gp-sphinx's deleted script."""
17+
source = tmp_path / "source"
18+
source.mkdir()
19+
(source / "conf.py").write_text(
20+
textwrap.dedent(
21+
f"""
22+
import runpy
23+
24+
_site = runpy.run_path({str(_ROOT / "docs" / "conf.py")!r})
25+
extensions = [
26+
name
27+
for name in _site["extensions"]
28+
if name == "sphinx_inline_tabs"
29+
]
30+
html_theme = "basic"
31+
project = "asset-test"
32+
setup = _site["setup"]
33+
"""
34+
),
35+
encoding="utf-8",
36+
)
37+
(source / "index.rst").write_text(
38+
textwrap.dedent(
39+
"""
40+
Asset test
41+
==========
42+
43+
.. tab:: Python plan
44+
45+
Typed operation
46+
47+
.. tab:: Compiled tmux sequence
48+
49+
Rendered command
50+
"""
51+
),
52+
encoding="utf-8",
53+
)
54+
55+
app = SphinxTestApp(
56+
srcdir=source,
57+
builddir=tmp_path / "_build",
58+
buildername="html",
59+
freshenv=True,
60+
)
61+
try:
62+
app.build()
63+
output = tmp_path / "_build" / "html"
64+
html = (output / "index.html").read_text(encoding="utf-8")
65+
finally:
66+
app.cleanup()
67+
68+
assert 'class="tab-set' in html
69+
assert "_static/tabs.css" in html
70+
assert "_static/tabs.js" not in html

0 commit comments

Comments
 (0)