Skip to content

Commit 13d85fc

Browse files
flaportclaude
andcommitted
fix crossrefs and defaults mixins
- crossrefs: remove recursive submodule search, support explicit crossref_modules list in theme config (defaults to top-level package) - defaults: use config["mdx_configs"] directly instead of .get() to ensure extensions are actually picked up by mkdocs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ef9e10c commit 13d85fc

2 files changed

Lines changed: 41 additions & 57 deletions

File tree

shadcn/plugins/mixins/crossrefs.py

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -20,58 +20,60 @@
2020
class CrossRefsMixin(Mixin):
2121
"""Auto-link backtick references to mkdocstrings anchors.
2222
23-
When mkdocstrings is configured, this mixin inspects the packages found
24-
under the handler's `paths` config and auto-converts backtick references
25-
like `pkg.SomeClass` into mkdocstrings cross-reference links
26-
[`pkg.SomeClass`][pkg.SomeClass].
27-
28-
Supports an `aliases` dict in the theme config for project-specific
29-
name mappings (e.g. `compute_modes` -> `pkg.compute_modes_impl`).
23+
When mkdocstrings is configured, this mixin auto-converts backtick
24+
references like `SomeClass` into mkdocstrings cross-reference links
25+
[`SomeClass`][pkg.SomeClass].
26+
27+
Configure via theme config:
28+
crossref_modules: list of dotted module names to search
29+
(default: auto-discovered top-level packages from mkdocstrings paths)
30+
crossref_aliases: dict mapping short names to fully qualified names
3031
"""
3132

3233
crossrefs_modules: List = []
3334
crossrefs_aliases: Dict[str, str] = {}
3435
crossrefs_activated: bool = False
35-
crossrefs_package_name: Optional[str] = None
3636

3737
def on_config(self, config: MkDocsConfig):
3838
plugin = config["plugins"].get("mkdocstrings", None)
3939
if plugin is None:
4040
return super().on_config(config)
4141

42-
# Get the aliases from theme config
4342
self.crossrefs_aliases = config.theme.get("crossref_aliases", {})
44-
45-
# Find package names from mkdocstrings paths
46-
handler_config = plugin.config.get("handlers", {}).get("python", {})
47-
paths = handler_config.get("paths", [])
48-
4943
self.crossrefs_modules = []
50-
self.crossrefs_package_name = None
5144

52-
for path in paths:
53-
# Try to discover top-level packages in the given paths
45+
# If user specified explicit modules, use those
46+
explicit_modules = config.theme.get("crossref_modules", None)
47+
48+
if explicit_modules is not None:
49+
for mod_name in explicit_modules:
50+
try:
51+
mod = importlib.import_module(mod_name)
52+
self.crossrefs_modules.append((mod_name, mod))
53+
logger.info(f"Cross-refs: loaded module '{mod_name}'.")
54+
except Exception as e:
55+
logger.warning(f"Cross-refs: could not import '{mod_name}': {e}")
56+
else:
57+
# Auto-discover top-level packages from mkdocstrings paths
5458
import os
5559

56-
if not os.path.isdir(path):
57-
continue
58-
for entry in sorted(os.listdir(path)):
59-
entry_path = os.path.join(path, entry)
60-
if os.path.isdir(entry_path) and os.path.isfile(
61-
os.path.join(entry_path, "__init__.py")
62-
):
63-
try:
64-
mod = importlib.import_module(entry)
65-
self.crossrefs_modules.append((entry, mod))
66-
if self.crossrefs_package_name is None:
67-
self.crossrefs_package_name = entry
68-
logger.info(
69-
f"Cross-refs: loaded module '{entry}' for auto-linking."
70-
)
71-
except Exception as e:
72-
logger.debug(
73-
f"Cross-refs: could not import '{entry}': {e}"
74-
)
60+
handler_config = plugin.config.get("handlers", {}).get("python", {})
61+
paths = handler_config.get("paths", [])
62+
63+
for path in paths:
64+
if not os.path.isdir(path):
65+
continue
66+
for entry in sorted(os.listdir(path)):
67+
entry_path = os.path.join(path, entry)
68+
if os.path.isdir(entry_path) and os.path.isfile(
69+
os.path.join(entry_path, "__init__.py")
70+
):
71+
try:
72+
mod = importlib.import_module(entry)
73+
self.crossrefs_modules.append((entry, mod))
74+
logger.info(f"Cross-refs: loaded module '{entry}'.")
75+
except Exception as e:
76+
logger.debug(f"Cross-refs: could not import '{entry}': {e}")
7577

7678
self.crossrefs_activated = len(self.crossrefs_modules) > 0
7779

@@ -85,7 +87,6 @@ def on_config(self, config: MkDocsConfig):
8587

8688
def _resolve_ref(self, name: str) -> Optional[str]:
8789
"""Resolve a backtick name to its fully qualified mkdocstrings anchor."""
88-
# Strip leading package prefix if present
8990
*prefix, short = name.split(".")
9091
if prefix and prefix[0] not in {n for n, _ in self.crossrefs_modules}:
9192
return None
@@ -94,22 +95,10 @@ def _resolve_ref(self, name: str) -> Optional[str]:
9495
if short in self.crossrefs_aliases:
9596
return self.crossrefs_aliases[short]
9697

97-
# Search through loaded modules and their submodules
98+
# Check each module directly — no recursion
9899
for mod_name, mod in self.crossrefs_modules:
99100
if hasattr(mod, short):
100101
return f"{mod_name}.{short}"
101-
# Check submodules
102-
for attr_name in dir(mod):
103-
attr = getattr(mod, attr_name, None)
104-
if (
105-
attr is not None
106-
and hasattr(attr, "__module__")
107-
and hasattr(attr, short)
108-
):
109-
# It's a submodule that has this name
110-
submod_name = f"{mod_name}.{attr_name}"
111-
if hasattr(attr, short):
112-
return f"{submod_name}.{short}"
113102

114103
return None
115104

@@ -131,10 +120,8 @@ def on_page_markdown(
131120
blocks = markdown.split("```")
132121
for i, block in enumerate(blocks):
133122
if i % 2 == 0:
134-
# Process non-code blocks
135123
blocks[i] = self._insert_cross_refs(block)
136124
else:
137-
# Restore code block delimiters
138125
blocks[i] = f"```{block}```"
139126

140127
markdown = "".join(blocks)

shadcn/plugins/mixins/defaults.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,11 @@ def _inject_markdown_extensions(self, config: MkDocsConfig):
6868
if isinstance(ext, str):
6969
existing.add(ext)
7070

71-
# mdx_configs holds extension options
72-
mdx_configs = config.get("mdx_configs", {})
73-
7471
for ext_name, ext_defaults in DEFAULT_MARKDOWN_EXTENSIONS.items():
7572
if ext_name not in existing:
7673
config.markdown_extensions.append(ext_name)
77-
if ext_defaults and ext_name not in mdx_configs:
78-
mdx_configs[ext_name] = ext_defaults
74+
if ext_defaults and ext_name not in config["mdx_configs"]:
75+
config["mdx_configs"][ext_name] = ext_defaults
7976
logger.debug(f"Added default markdown extension: {ext_name}")
8077

8178
def _inject_mkdocstrings_defaults(self, config: MkDocsConfig):

0 commit comments

Comments
 (0)