codekingpro/portable-devtools
114k
1from __future__ import annotations2 3from collections.abc import MutableMapping as MutableMappingABC4from pathlib import Path5from typing import Any, Callable, Iterable, MutableMapping, TypedDict, cast6 7EnvType = MutableMapping[str, Any] # note: could use TypeAlias in python 3.108"""Type for the environment sandbox used in parsing and rendering,9which stores mutable variables for use by plugins and rules.10"""11 12 13class OptionsType(TypedDict):14 """Options for parsing."""15 16 maxNesting: int17 """Internal protection, recursion limit."""18 html: bool19 """Enable HTML tags in source."""20 linkify: bool21 """Enable autoconversion of URL-like texts to links."""22 typographer: bool23 """Enable smartquotes and replacements."""24 quotes: str25 """Quote characters."""26 xhtmlOut: bool27 """Use '/' to close single tags (<br />)."""28 breaks: bool29 """Convert newlines in paragraphs into <br>."""30 langPrefix: str31 """CSS language prefix for fenced blocks."""32 highlight: Callable[[str, str, str], str] | None33 """Highlighter function: (content, lang, attrs) -> str."""34 35 36class PresetType(TypedDict):37 """Preset configuration for markdown-it."""38 39 options: OptionsType40 """Options for parsing."""41 components: MutableMapping[str, MutableMapping[str, list[str]]]42 """Components for parsing and rendering."""43 44 45class OptionsDict(MutableMappingABC): # type: ignore46 """A dictionary, with attribute access to core markdownit configuration options."""47 48 # Note: ideally we would probably just remove attribute access entirely,49 # but we keep it for backwards compatibility.50 51 def __init__(self, options: OptionsType) -> None:52 self._options = cast(OptionsType, dict(options))53 54 def __getitem__(self, key: str) -> Any:55 return self._options[key] # type: ignore[literal-required]56 57 def __setitem__(self, key: str, value: Any) -> None:58 self._options[key] = value # type: ignore[literal-required]59 60 def __delitem__(self, key: str) -> None:61 del self._options[key] # type: ignore62 63 def __iter__(self) -> Iterable[str]: # type: ignore64 return iter(self._options)65 66 def __len__(self) -> int:67 return len(self._options)68 69 def __repr__(self) -> str:70 return repr(self._options)71 72 def __str__(self) -> str:73 return str(self._options)74 75 @property76 def maxNesting(self) -> int:77 """Internal protection, recursion limit."""78 return self._options["maxNesting"]79 80 @maxNesting.setter81 def maxNesting(self, value: int) -> None:82 self._options["maxNesting"] = value83 84 @property85 def html(self) -> bool:86 """Enable HTML tags in source."""87 return self._options["html"]88 89 @html.setter90 def html(self, value: bool) -> None:91 self._options["html"] = value92 93 @property94 def linkify(self) -> bool:95 """Enable autoconversion of URL-like texts to links."""96 return self._options["linkify"]97 98 @linkify.setter99 def linkify(self, value: bool) -> None:100 self._options["linkify"] = value101 102 @property103 def typographer(self) -> bool:104 """Enable smartquotes and replacements."""105 return self._options["typographer"]106 107 @typographer.setter108 def typographer(self, value: bool) -> None:109 self._options["typographer"] = value110 111 @property112 def quotes(self) -> str:113 """Quote characters."""114 return self._options["quotes"]115 116 @quotes.setter117 def quotes(self, value: str) -> None:118 self._options["quotes"] = value119 120 @property121 def xhtmlOut(self) -> bool:122 """Use '/' to close single tags (<br />)."""123 return self._options["xhtmlOut"]124 125 @xhtmlOut.setter126 def xhtmlOut(self, value: bool) -> None:127 self._options["xhtmlOut"] = value128 129 @property130 def breaks(self) -> bool:131 """Convert newlines in paragraphs into <br>."""132 return self._options["breaks"]133 134 @breaks.setter135 def breaks(self, value: bool) -> None:136 self._options["breaks"] = value137 138 @property139 def langPrefix(self) -> str:140 """CSS language prefix for fenced blocks."""141 return self._options["langPrefix"]142 143 @langPrefix.setter144 def langPrefix(self, value: str) -> None:145 self._options["langPrefix"] = value146 147 @property148 def highlight(self) -> Callable[[str, str, str], str] | None:149 """Highlighter function: (content, langName, langAttrs) -> escaped HTML."""150 return self._options["highlight"]151 152 @highlight.setter153 def highlight(self, value: Callable[[str, str, str], str] | None) -> None:154 self._options["highlight"] = value155 156 157def read_fixture_file(path: str | Path) -> list[list[Any]]:158 text = Path(path).read_text(encoding="utf-8")159 tests = []160 section = 0161 last_pos = 0162 lines = text.splitlines(keepends=True)163 for i in range(len(lines)):164 if lines[i].rstrip() == ".":165 if section == 0:166 tests.append([i, lines[i - 1].strip()])167 section = 1168 elif section == 1:169 tests[-1].append("".join(lines[last_pos + 1 : i]))170 section = 2171 elif section == 2:172 tests[-1].append("".join(lines[last_pos + 1 : i]))173 section = 0174 175 last_pos = i176 return tests177 