[文档]defconvert_attrs(value:Any)->Any:"""Convert Token.attrs set as ``None`` or ``[[key, value], ...]`` to a dict. This improves compatibility with upstream markdown-it. """ifnotvalue:return{}ifisinstance(value,list):returndict(value)returnvalue
[文档]@attr.s(slots=True)classToken:# Type of the token (string, e.g. "paragraph_open")type:str=attr.ib()# html tag name, e.g. "p"tag:str=attr.ib()# Level change (number in {-1, 0, 1} set), where:# - `1` means the tag is opening# - `0` means the tag is self-closing# - `-1` means the tag is closingnesting:int=attr.ib()# Html attributes. Note this differs from the upstream "list of lists" formatattrs:Dict[str,Union[str,int,float]]=attr.ib(factory=dict,converter=convert_attrs)# Source map info. Format: `[ line_begin, line_end ]`map:Optional[List[int]]=attr.ib(default=None)# nesting level, the same as `state.level`level:int=attr.ib(default=0)# An array of child nodes (inline and img tokens)children:Optional[List["Token"]]=attr.ib(default=None)# In a case of self-closing tag (code, html, fence, etc.),# it has contents of this tag.content:str=attr.ib(default="")# '*' or '_' for emphasis, fence string for fence, etc.markup:str=attr.ib(default="")# Additional information:# - Info string for "fence" tokens# - The value "auto" for autolink "link_open" and "link_close" tokensinfo:str=attr.ib(default="")# A place for plugins to store any arbitrary datameta:dict=attr.ib(factory=dict)# True for block-level tokens, false for inline tokens.# Used in renderer to calculate line breaksblock:bool=attr.ib(default=False)# If it's true, ignore this element when rendering.# Used for tight lists to hide paragraphs.hidden:bool=attr.ib(default=False)
[文档]defattrIndex(self,name:str)->int:warnings.warn("Token.attrIndex should not be used, since Token.attrs is a dictionary",UserWarning,)ifnamenotinself.attrs:return-1returnlist(self.attrs.keys()).index(name)
[文档]defattrItems(self)->List[Tuple[str,Union[str,int,float]]]:"""Get (key, value) list of attrs."""returnlist(self.attrs.items())
[文档]defattrPush(self,attrData:Tuple[str,Union[str,int,float]])->None:"""Add `[ name, value ]` attribute to list. Init attrs if necessary."""name,value=attrDataself.attrSet(name,value)
[文档]defattrSet(self,name:str,value:Union[str,int,float])->None:"""Set `name` attribute to `value`. Override old value if exists."""self.attrs[name]=value
[文档]defattrGet(self,name:str)->Union[None,str,int,float]:"""Get the value of attribute `name`, or null if it does not exist."""returnself.attrs.get(name,None)
[文档]defattrJoin(self,name:str,value:str)->None:"""Join value to existing attribute via space. Or create new attribute if not exists. Useful to operate with token classes. """ifnameinself.attrs:current=self.attrs[name]ifnotisinstance(current,str):raiseTypeError(f"existing attr 'name' is not a str: {self.attrs[name]}")self.attrs[name]=f"{current}{value}"else:self.attrs[name]=value
[文档]defcopy(self)->"Token":"""Return a shallow copy of the instance."""returnattr.evolve(self)
[文档]defas_dict(self,*,children:bool=True,as_upstream:bool=True,meta_serializer:Optional[Callable[[dict],Any]]=None,filter:Optional[Callable[[attr.Attribute,Any],bool]]=None,dict_factory:Type[MutableMapping[str,Any]]=dict,)->MutableMapping[str,Any]:"""Return the token as a dictionary. :param children: Also convert children to dicts :param as_upstream: Ensure the output dictionary is equal to that created by markdown-it For example, attrs are converted to null or lists :param meta_serializer: hook for serializing ``Token.meta`` :param filter: A callable whose return code determines whether an attribute or element is included (``True``) or dropped (``False``). Is called with the `attr.Attribute` as the first argument and the value as the second argument. :param dict_factory: A callable to produce dictionaries from. For example, to produce ordered dictionaries instead of normal Python dictionaries, pass in ``collections.OrderedDict``. """mapping=attr.asdict(self,recurse=False,filter=filter,dict_factory=dict_factory)ifas_upstreamand"attrs"inmapping:mapping["attrs"]=(Noneifnotmapping["attrs"]else[[k,v]fork,vinmapping["attrs"].items()])ifmeta_serializerand"meta"inmapping:mapping["meta"]=meta_serializer(mapping["meta"])ifchildrenandmapping.get("children",None):mapping["children"]=[child.as_dict(children=children,filter=filter,dict_factory=dict_factory,as_upstream=as_upstream,meta_serializer=meta_serializer,)forchildinmapping["children"]]returnmapping
[文档]@classmethoddeffrom_dict(cls,dct:MutableMapping[str,Any])->"Token":"""Convert a dict to a Token."""token=cls(**dct)iftoken.children:token.children=[cls.from_dict(c)forcintoken.children]# type: ignore[arg-type]returntoken
[文档]@attr.s(slots=True)classNestedTokens:"""A class that closely resembles a Token, but for a an opening/closing Token pair, and their containing children. """opening:Token=attr.ib()closing:Token=attr.ib()children:List[Union[Token,"NestedTokens"]]=attr.ib(factory=list)def__getattr__(self,name):returngetattr(self.opening,name)
[文档]defattrGet(self,name:str)->Union[None,str,int,float]:""" Get the value of attribute `name`, or null if it does not exist."""returnself.opening.attrGet(name)
[文档]defnest_tokens(tokens:List[Token])->List[Union[Token,NestedTokens]]:"""Convert the token stream to a list of tokens and nested tokens. ``NestedTokens`` contain the open and close tokens and a list of children of all tokens in between (recursively nested) """warnings.warn("`markdown_it.token.nest_tokens` and `markdown_it.token.NestedTokens`"" are deprecated. Please migrate to `markdown_it.tree.SyntaxTreeNode`",DeprecationWarning,)output:List[Union[Token,NestedTokens]]=[]tokens=list(reversed(tokens))whiletokens:token=tokens.pop()iftoken.nesting==0:token=token.copy()output.append(token)iftoken.children:# Ignore type checkers because `nest_tokens` doesn't respect# typing of `Token.children`. We add `NestedTokens` into a# `List[Token]` here.token.children=nest_tokens(token.children)# type: ignorecontinueasserttoken.nesting==1,token.nestingnested_tokens=[token]nesting=1whiletokensandnesting!=0:token=tokens.pop()nested_tokens.append(token)nesting+=token.nestingifnesting!=0:raiseValueError(f"unclosed tokens starting {nested_tokens[0]}")child=NestedTokens(nested_tokens[0],nested_tokens[-1])output.append(child)child.children=nest_tokens(nested_tokens[1:-1])returnoutput