Spaces:
Paused
Paused
| from __future__ import annotations | |
| from collections.abc import Callable, MutableMapping | |
| import dataclasses as dc | |
| from typing import Any, Literal | |
| import warnings | |
| from markdown_it._compat import DATACLASS_KWARGS | |
| def convert_attrs(value: Any) -> Any: | |
| """Convert Token.attrs set as ``None`` or ``[[key, value], ...]`` to a dict. | |
| This improves compatibility with upstream markdown-it. | |
| """ | |
| if not value: | |
| return {} | |
| if isinstance(value, list): | |
| return dict(value) | |
| return value | |
| class Token: | |
| type: str | |
| """Type of the token (string, e.g. "paragraph_open")""" | |
| tag: str | |
| """HTML tag name, e.g. 'p'""" | |
| nesting: Literal[-1, 0, 1] | |
| """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 closing | |
| """ | |
| attrs: dict[str, str | int | float] = dc.field(default_factory=dict) | |
| """HTML attributes. | |
| Note this differs from the upstream "list of lists" format, | |
| although than an instance can still be initialised with this format. | |
| """ | |
| map: list[int] | None = None | |
| """Source map info. Format: `[ line_begin, line_end ]`""" | |
| level: int = 0 | |
| """Nesting level, the same as `state.level`""" | |
| children: list[Token] | None = None | |
| """Array of child nodes (inline and img tokens).""" | |
| content: str = "" | |
| """Inner content, in the case of a self-closing tag (code, html, fence, etc.),""" | |
| markup: str = "" | |
| """'*' or '_' for emphasis, fence string for fence, etc.""" | |
| info: str = "" | |
| """Additional information: | |
| - Info string for "fence" tokens | |
| - The value "auto" for autolink "link_open" and "link_close" tokens | |
| - The string value of the item marker for ordered-list "list_item_open" tokens | |
| """ | |
| meta: dict[Any, Any] = dc.field(default_factory=dict) | |
| """A place for plugins to store any arbitrary data""" | |
| block: bool = False | |
| """True for block-level tokens, false for inline tokens. | |
| Used in renderer to calculate line breaks | |
| """ | |
| hidden: bool = False | |
| """If true, ignore this element when rendering. | |
| Used for tight lists to hide paragraphs. | |
| """ | |
| def __post_init__(self) -> None: | |
| self.attrs = convert_attrs(self.attrs) | |
| def attrIndex(self, name: str) -> int: | |
| warnings.warn( # noqa: B028 | |
| "Token.attrIndex should not be used, since Token.attrs is a dictionary", | |
| UserWarning, | |
| ) | |
| if name not in self.attrs: | |
| return -1 | |
| return list(self.attrs.keys()).index(name) | |
| def attrItems(self) -> list[tuple[str, str | int | float]]: | |
| """Get (key, value) list of attrs.""" | |
| return list(self.attrs.items()) | |
| def attrPush(self, attrData: tuple[str, str | int | float]) -> None: | |
| """Add `[ name, value ]` attribute to list. Init attrs if necessary.""" | |
| name, value = attrData | |
| self.attrSet(name, value) | |
| def attrSet(self, name: str, value: str | int | float) -> None: | |
| """Set `name` attribute to `value`. Override old value if exists.""" | |
| self.attrs[name] = value | |
| def attrGet(self, name: str) -> None | str | int | float: | |
| """Get the value of attribute `name`, or null if it does not exist.""" | |
| return self.attrs.get(name, None) | |
| def attrJoin(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. | |
| """ | |
| if name in self.attrs: | |
| current = self.attrs[name] | |
| if not isinstance(current, str): | |
| raise TypeError( | |
| f"existing attr 'name' is not a str: {self.attrs[name]}" | |
| ) | |
| self.attrs[name] = f"{current} {value}" | |
| else: | |
| self.attrs[name] = value | |
| def copy(self, **changes: Any) -> Token: | |
| """Return a shallow copy of the instance.""" | |
| return dc.replace(self, **changes) | |
| def as_dict( | |
| self, | |
| *, | |
| children: bool = True, | |
| as_upstream: bool = True, | |
| meta_serializer: Callable[[dict[Any, Any]], Any] | None = None, | |
| filter: Callable[[str, Any], bool] | None = None, | |
| dict_factory: Callable[..., 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 (key, value) pair. | |
| :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 = dict_factory((f.name, getattr(self, f.name)) for f in dc.fields(self)) | |
| if filter: | |
| mapping = dict_factory((k, v) for k, v in mapping.items() if filter(k, v)) | |
| if as_upstream and "attrs" in mapping: | |
| mapping["attrs"] = ( | |
| None | |
| if not mapping["attrs"] | |
| else [[k, v] for k, v in mapping["attrs"].items()] | |
| ) | |
| if meta_serializer and "meta" in mapping: | |
| mapping["meta"] = meta_serializer(mapping["meta"]) | |
| if children and mapping.get("children", None): | |
| mapping["children"] = [ | |
| child.as_dict( | |
| children=children, | |
| filter=filter, | |
| dict_factory=dict_factory, | |
| as_upstream=as_upstream, | |
| meta_serializer=meta_serializer, | |
| ) | |
| for child in mapping["children"] | |
| ] | |
| return mapping | |
| def from_dict(cls, dct: MutableMapping[str, Any]) -> Token: | |
| """Convert a dict to a Token.""" | |
| token = cls(**dct) | |
| if token.children: | |
| token.children = [cls.from_dict(c) for c in token.children] # type: ignore[arg-type] | |
| return token | |