2727
2828_REGEX_META_CHARS = set (r"()[]{}?*+|.^$" )
2929_CHARREF_PREFIX = re .compile (r"(#[0-9]{1,7};|#[xX][0-9a-fA-F]+;|[^\t\n\f <&#;]{1,32};)" )
30+ DEFAULT_MAX_EMPHASIS_DEPTH = 20
3031
3132AUTO_EMAIL = (
3233 r"""<[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9]"""
@@ -84,10 +85,11 @@ class InlineParser(Parser[InlineState]):
8485 "linebreak" ,
8586 )
8687
87- def __init__ (self , hard_wrap : bool = False ) -> None :
88+ def __init__ (self , hard_wrap : bool = False , max_emphasis_depth : int = DEFAULT_MAX_EMPHASIS_DEPTH ) -> None :
8889 super (InlineParser , self ).__init__ ()
8990
9091 self .hard_wrap = hard_wrap
92+ self .max_emphasis_depth = max_emphasis_depth
9193 self ._fast_trigger_chars : Optional [Set [str ]] = None
9294 self ._fast_trigger_re : Optional [re .Pattern [str ]] = None
9395 self ._fast_trigger_re_chars : Optional [Tuple [str , ...]] = None
@@ -380,7 +382,11 @@ def parse(self, state: InlineState) -> List[Dict[str, Any]]:
380382 self .process_text (state .src , state )
381383 elif pos < len (state .src ):
382384 self .process_text (state .src [pos :], state )
383- state .tokens = _finalize_emphasis_tokens (state .tokens , "emphasis" in self .rules )
385+ state .tokens = _finalize_emphasis_tokens (
386+ state .tokens ,
387+ "emphasis" in self .rules ,
388+ self .max_emphasis_depth ,
389+ )
384390 return state .tokens
385391
386392 def _find_fast_text_end (self , src : str , pos : int ) -> Optional [int ]:
@@ -542,7 +548,11 @@ class _Delimiter:
542548 orig_length : int = 0
543549
544550
545- def _finalize_emphasis_tokens (tokens : List [Dict [str , Any ]], enabled : bool ) -> List [Dict [str , Any ]]:
551+ def _finalize_emphasis_tokens (
552+ tokens : List [Dict [str , Any ]],
553+ enabled : bool ,
554+ max_depth : int = DEFAULT_MAX_EMPHASIS_DEPTH ,
555+ ) -> List [Dict [str , Any ]]:
546556 if not enabled :
547557 return _clean_emphasis_tokens (tokens )
548558 if not _contains_emphasis_marker (tokens ):
@@ -559,7 +569,7 @@ def _finalize_emphasis_tokens(tokens: List[Dict[str, Any]], enabled: bool) -> Li
559569 parts .append (_clean_emphasis_token (token ))
560570 source_pos += _emphasis_source_length (token )
561571
562- _process_emphasis_delimiters (parts , delimiters )
572+ _process_emphasis_delimiters (parts , delimiters , max_depth )
563573 return _merge_text_tokens (parts )
564574
565575
@@ -639,7 +649,11 @@ def _next_delimiter_run(text: str, pos: int) -> int:
639649 return pos
640650
641651
642- def _process_emphasis_delimiters (parts : List [Dict [str , Any ]], delimiters : List [_Delimiter ]) -> None :
652+ def _process_emphasis_delimiters (
653+ parts : List [Dict [str , Any ]],
654+ delimiters : List [_Delimiter ],
655+ max_depth : int ,
656+ ) -> None :
643657 closer_pos = 0
644658 openers_bottom : Dict [Tuple [str , int , bool ], int ] = {}
645659 while closer_pos < len (delimiters ):
@@ -688,9 +702,12 @@ def _process_emphasis_delimiters(parts: List[Dict[str, Any]], delimiters: List[_
688702 closer_pos += 1
689703 continue
690704
705+ children = parts [opener .index + 1 : closer .index ]
706+ if max_depth > 0 and _emphasis_depth (children ) >= max_depth :
707+ closer_pos += 1
708+ continue
691709 opener_text ["raw" ] = opener_text ["raw" ][:- use_length ]
692710 closer_text ["raw" ] = closer_text ["raw" ][use_length :]
693- children = parts [opener .index + 1 : closer .index ]
694711 if use_length == 2 :
695712 node = {"type" : "strong" , "children" : children }
696713 else :
@@ -721,6 +738,21 @@ def _process_emphasis_delimiters(parts: List[Dict[str, Any]], delimiters: List[_
721738 closer_pos += 1
722739
723740
741+ def _emphasis_depth (tokens : List [Dict [str , Any ]]) -> int :
742+ max_depth = 0
743+ stack = [(token , 0 ) for token in tokens ]
744+ while stack :
745+ token , depth = stack .pop ()
746+ token_type = token ["type" ]
747+ if token_type in ("emphasis" , "strong" ):
748+ depth += 1
749+ if depth > max_depth :
750+ max_depth = depth
751+ for child in token .get ("children" , ()):
752+ stack .append ((child , depth ))
753+ return max_depth
754+
755+
724756def _has_strong_enabled (parts : List [Dict [str , Any ]], opener : _Delimiter , closer : _Delimiter ) -> bool :
725757 return len (_text_raw (parts [opener .index ])) >= 2 and len (_text_raw (parts [closer .index ])) >= 2
726758
0 commit comments