22
33from __future__ import annotations
44
5- import re
65from dataclasses import dataclass
76
87# ---------------------------------------------------------------------------
@@ -20,14 +19,6 @@ class TextSpan:
2019
2120 text : str
2221
23- def as_markdown (self ) -> str :
24- """Render back to markdown.
25-
26- Returns:
27- A markdown string.
28- """
29- return self .text
30-
3122
3223@dataclass (frozen = True , slots = True , kw_only = True )
3324class BoldSpan :
@@ -39,15 +30,6 @@ class BoldSpan:
3930
4031 children : tuple [Span , ...]
4132
42- def as_markdown (self ) -> str :
43- """Render back to markdown.
44-
45- Returns:
46- A markdown string.
47- """
48- inner = "" .join (c .as_markdown () for c in self .children )
49- return f"**{ inner } **"
50-
5133
5234@dataclass (frozen = True , slots = True , kw_only = True )
5335class ItalicSpan :
@@ -59,15 +41,6 @@ class ItalicSpan:
5941
6042 children : tuple [Span , ...]
6143
62- def as_markdown (self ) -> str :
63- """Render back to markdown.
64-
65- Returns:
66- A markdown string.
67- """
68- inner = "" .join (c .as_markdown () for c in self .children )
69- return f"*{ inner } *"
70-
7144
7245@dataclass (frozen = True , slots = True , kw_only = True )
7346class StrikethroughSpan :
@@ -79,15 +52,6 @@ class StrikethroughSpan:
7952
8053 children : tuple [Span , ...]
8154
82- def as_markdown (self ) -> str :
83- """Render back to markdown.
84-
85- Returns:
86- A markdown string.
87- """
88- inner = "" .join (c .as_markdown () for c in self .children )
89- return f"~~{ inner } ~~"
90-
9155
9256@dataclass (frozen = True , slots = True , kw_only = True )
9357class CodeSpan :
@@ -99,14 +63,6 @@ class CodeSpan:
9963
10064 code : str
10165
102- def as_markdown (self ) -> str :
103- """Render back to markdown.
104-
105- Returns:
106- A markdown string.
107- """
108- return f"`{ self .code } `"
109-
11066
11167@dataclass (frozen = True , slots = True , kw_only = True )
11268class LinkSpan :
@@ -120,15 +76,6 @@ class LinkSpan:
12076 children : tuple [Span , ...]
12177 target : str
12278
123- def as_markdown (self ) -> str :
124- """Render back to markdown.
125-
126- Returns:
127- A markdown string.
128- """
129- inner = "" .join (c .as_markdown () for c in self .children )
130- return f"[{ inner } ]({ self .target } )"
131-
13279
13380@dataclass (frozen = True , slots = True , kw_only = True )
13481class ImageSpan :
@@ -142,15 +89,6 @@ class ImageSpan:
14289 children : tuple [Span , ...]
14390 src : str
14491
145- def as_markdown (self ) -> str :
146- """Render back to markdown.
147-
148- Returns:
149- A markdown string.
150- """
151- inner = "" .join (c .as_markdown () for c in self .children )
152- return f""
153-
15492
15593@dataclass (frozen = True , slots = True , kw_only = True )
15694class LineBreakSpan :
@@ -162,14 +100,6 @@ class LineBreakSpan:
162100
163101 soft : bool
164102
165- def as_markdown (self ) -> str :
166- """Render back to markdown.
167-
168- Returns:
169- A markdown string.
170- """
171- return "\n " if self .soft else " \n "
172-
173103
174104#: Union of all inline span types.
175105Span = (
@@ -184,36 +114,6 @@ def as_markdown(self) -> str:
184114)
185115
186116
187- def _spans_as_markdown (spans : tuple [Span , ...]) -> str :
188- """Render a sequence of spans back to markdown.
189-
190- Args:
191- spans: The inline spans to render.
192-
193- Returns:
194- A markdown string.
195- """
196- return "" .join (s .as_markdown () for s in spans )
197-
198-
199- _BACKTICK_FENCE_RE = re .compile (r"^(`{3,})" , re .MULTILINE )
200-
201-
202- def _fence_for (content : str ) -> str :
203- """Return a backtick fence long enough to wrap *content* safely.
204-
205- Args:
206- content: The code block content that may contain backtick fences.
207-
208- Returns:
209- A backtick fence string (at least 3 backticks).
210- """
211- max_run = 3
212- for m in _BACKTICK_FENCE_RE .finditer (content ):
213- max_run = max (max_run , len (m .group (1 )) + 1 )
214- return "`" * max_run
215-
216-
217117# ---------------------------------------------------------------------------
218118# Block types
219119# ---------------------------------------------------------------------------
@@ -248,25 +148,6 @@ class FrontMatter:
248148 title : str | None
249149 component_previews : tuple [ComponentPreview , ...]
250150
251- def as_markdown (self ) -> str :
252- """Render back to markdown.
253-
254- Returns:
255- A markdown string.
256- """
257- import yaml
258-
259- data : dict [str , object ] = {}
260- if self .components :
261- data ["components" ] = list (self .components )
262- if self .only_low_level :
263- data ["only_low_level" ] = [True ]
264- if self .title is not None :
265- data ["title" ] = self .title
266- for preview in self .component_previews :
267- data [preview .name ] = preview .source
268- return f"---\n { yaml .dump (data , default_flow_style = False , sort_keys = False ).rstrip ()} \n ---"
269-
270151
271152@dataclass (frozen = True , slots = True , kw_only = True )
272153class CodeBlock :
@@ -282,18 +163,6 @@ class CodeBlock:
282163 flags : tuple [str , ...]
283164 content : str
284165
285- def as_markdown (self ) -> str :
286- """Render back to markdown.
287-
288- Returns:
289- A markdown string.
290- """
291- info = self .language or ""
292- if self .flags :
293- info = f"{ info } { ' ' .join (self .flags )} " if info else " " .join (self .flags )
294- fence = _fence_for (self .content )
295- return f"{ fence } { info } \n { self .content } \n { fence } "
296-
297166
298167@dataclass (frozen = True , slots = True , kw_only = True )
299168class DirectiveBlock :
@@ -311,16 +180,6 @@ class DirectiveBlock:
311180 args : tuple [str , ...]
312181 content : str
313182
314- def as_markdown (self ) -> str :
315- """Render back to markdown.
316-
317- Returns:
318- A markdown string.
319- """
320- info_parts = ["md" , self .name , * self .args ]
321- fence = _fence_for (self .content )
322- return f"{ fence } { ' ' .join (info_parts )} \n { self .content } \n { fence } "
323-
324183
325184@dataclass (frozen = True , slots = True , kw_only = True )
326185class HeadingBlock :
@@ -334,14 +193,6 @@ class HeadingBlock:
334193 level : int
335194 children : tuple [Span , ...]
336195
337- def as_markdown (self ) -> str :
338- """Render back to markdown.
339-
340- Returns:
341- A markdown string.
342- """
343- return f"{ '#' * self .level } { _spans_as_markdown (self .children )} "
344-
345196
346197@dataclass (frozen = True , slots = True , kw_only = True )
347198class TextBlock :
@@ -353,14 +204,6 @@ class TextBlock:
353204
354205 children : tuple [Span , ...]
355206
356- def as_markdown (self ) -> str :
357- """Render back to markdown.
358-
359- Returns:
360- A markdown string.
361- """
362- return _spans_as_markdown (self .children )
363-
364207
365208@dataclass (frozen = True , slots = True , kw_only = True )
366209class ListItem :
@@ -387,22 +230,6 @@ class ListBlock:
387230 start : int | None
388231 items : tuple [ListItem , ...]
389232
390- def as_markdown (self ) -> str :
391- """Render back to markdown.
392-
393- Returns:
394- A markdown string.
395- """
396- lines : list [str ] = []
397- for i , item in enumerate (self .items ):
398- prefix = f"{ (self .start or 1 ) + i } . " if self .ordered else "- "
399- item_md = "\n \n " .join (child .as_markdown () for child in item .children )
400- first , * rest = item_md .split ("\n " )
401- lines .append (f"{ prefix } { first } " )
402- indent = " " * len (prefix )
403- lines .extend (f"{ indent } { line } " if line else "" for line in rest )
404- return "\n " .join (lines )
405-
406233
407234@dataclass (frozen = True , slots = True , kw_only = True )
408235class QuoteBlock :
@@ -414,15 +241,6 @@ class QuoteBlock:
414241
415242 children : tuple [Block , ...]
416243
417- def as_markdown (self ) -> str :
418- """Render back to markdown.
419-
420- Returns:
421- A markdown string.
422- """
423- inner = "\n \n " .join (child .as_markdown () for child in self .children )
424- return "\n " .join (f"> { line } " if line else ">" for line in inner .split ("\n " ))
425-
426244
427245@dataclass (frozen = True , slots = True , kw_only = True )
428246class TableCell :
@@ -447,15 +265,6 @@ class TableRow:
447265
448266 cells : tuple [TableCell , ...]
449267
450- def as_markdown (self ) -> str :
451- """Render back to markdown.
452-
453- Returns:
454- A markdown string.
455- """
456- cells = " | " .join (_spans_as_markdown (cell .children ) for cell in self .cells )
457- return f"| { cells } |"
458-
459268
460269@dataclass (frozen = True , slots = True , kw_only = True )
461270class TableBlock :
@@ -469,40 +278,11 @@ class TableBlock:
469278 header : TableRow
470279 rows : tuple [TableRow , ...]
471280
472- def as_markdown (self ) -> str :
473- """Render back to markdown.
474-
475- Returns:
476- A markdown string.
477- """
478- lines = [self .header .as_markdown ()]
479- sep_parts : list [str ] = []
480- for cell in self .header .cells :
481- if cell .align == "left" :
482- sep_parts .append (":---" )
483- elif cell .align == "right" :
484- sep_parts .append ("---:" )
485- elif cell .align == "center" :
486- sep_parts .append (":---:" )
487- else :
488- sep_parts .append ("---" )
489- lines .append (f"| { ' | ' .join (sep_parts )} |" )
490- lines .extend (row .as_markdown () for row in self .rows )
491- return "\n " .join (lines )
492-
493281
494282@dataclass (frozen = True , slots = True , kw_only = True )
495283class ThematicBreakBlock :
496284 """A thematic break (horizontal rule)."""
497285
498- def as_markdown (self ) -> str :
499- """Render back to markdown.
500-
501- Returns:
502- A markdown string.
503- """
504- return "---"
505-
506286
507287#: Union of all block types that can appear in a parsed document.
508288Block = (
@@ -544,15 +324,3 @@ def code_blocks(self) -> tuple[CodeBlock, ...]:
544324 def directives (self ) -> tuple [DirectiveBlock , ...]:
545325 """Return all directive blocks in the document."""
546326 return tuple (b for b in self .blocks if isinstance (b , DirectiveBlock ))
547-
548- def as_markdown (self ) -> str :
549- """Render the full document back to markdown.
550-
551- Returns:
552- A markdown string.
553- """
554- parts : list [str ] = []
555- if self .frontmatter :
556- parts .append (self .frontmatter .as_markdown ())
557- parts .extend (block .as_markdown () for block in self .blocks )
558- return "\n \n " .join (parts ) + "\n "
0 commit comments