@@ -625,7 +625,7 @@ def check_unpaired_math(repo_root: Path) -> list[str]:
625625}
626626
627627
628- def check_doxygen_commands_in_backticks (repo_root : Path ) -> list [str ]:
628+ def check_doxygen_commands_in_backticks (repo_root : Path ) -> list [str ]: # pylint: disable=too-many-locals
629629 """Check for Doxygen @/\\ commands inside backtick code spans.
630630
631631 Doxygen processes certain block commands even inside backtick code
@@ -708,6 +708,71 @@ def check_single_quote_in_backtick(repo_root: Path) -> list[str]:
708708 return errors
709709
710710
711+ # LaTeX commands that require AMSmath but are not reliably loaded by the
712+ # MathJax configuration (config.js). Use the standard alternatives instead.
713+ _AMSMATH_ONLY_CMDS = {
714+ "dfrac" : "frac" ,
715+ "tfrac" : "frac" ,
716+ "dbinom" : "binom" ,
717+ "tbinom" : "binom" ,
718+ "dddot" : "dot" ,
719+ "ddddot" : "dot" ,
720+ }
721+
722+
723+ def check_amsmath_in_doxygen_math (repo_root : Path ) -> list [str ]: # pylint: disable=too-many-locals
724+ """Flag AMSmath-only commands in Doxygen math that may not render."""
725+ doc_dir = repo_root / "docs" / "documentation"
726+ if not doc_dir .exists ():
727+ return []
728+
729+ ignored = _gitignored_docs (repo_root )
730+ # Match \f$...\f$ inline or content between \f[ and \f]
731+ inline_re = re .compile (r"\\f\$(.*?)\\f\$" )
732+ cmd_names = "|" .join (re .escape (c ) for c in sorted (_AMSMATH_ONLY_CMDS ))
733+ ams_re = re .compile (rf"\\({ cmd_names } )\b" )
734+
735+ errors = []
736+ for md_file in sorted (doc_dir .glob ("*.md" )):
737+ if md_file .name in ignored :
738+ continue
739+ text = md_file .read_text (encoding = "utf-8" )
740+ rel = md_file .relative_to (repo_root )
741+ in_code = False
742+ in_display = False
743+
744+ for i , line in enumerate (text .split ("\n " ), 1 ):
745+ if line .strip ().startswith ("```" ):
746+ in_code = not in_code
747+ continue
748+ if in_code :
749+ continue
750+
751+ # Check inline math \f$...\f$
752+ for m in inline_re .finditer (line ):
753+ for cm in ams_re .finditer (m .group (1 )):
754+ alt = _AMSMATH_ONLY_CMDS [cm .group (1 )]
755+ errors .append (
756+ f" { rel } :{ i } uses \\ { cm .group (1 )} (AMSmath) in"
757+ f" math. Fix: use \\ { alt } instead"
758+ )
759+
760+ # Check display math lines between \f[ and \f]
761+ if "\\ f[" in line :
762+ in_display = True
763+ if in_display :
764+ for cm in ams_re .finditer (line ):
765+ alt = _AMSMATH_ONLY_CMDS [cm .group (1 )]
766+ errors .append (
767+ f" { rel } :{ i } uses \\ { cm .group (1 )} (AMSmath) in"
768+ f" math. Fix: use \\ { alt } instead"
769+ )
770+ if "\\ f]" in line :
771+ in_display = False
772+
773+ return errors
774+
775+
711776def main ():
712777 repo_root = Path (__file__ ).resolve ().parents [2 ]
713778
@@ -721,6 +786,7 @@ def main():
721786 all_errors .extend (check_doxygen_percent (repo_root ))
722787 all_errors .extend (check_doxygen_commands_in_backticks (repo_root ))
723788 all_errors .extend (check_single_quote_in_backtick (repo_root ))
789+ all_errors .extend (check_amsmath_in_doxygen_math (repo_root ))
724790 all_errors .extend (check_section_anchors (repo_root ))
725791 all_errors .extend (check_physics_docs_coverage (repo_root ))
726792 all_errors .extend (check_identifier_refs (repo_root ))
0 commit comments