nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1import textwrap
2
3import pytest
4from markdown_it.token import Token
5
6import nixos_render_docs as nrd
7from nixos_render_docs.src_error import SrcError
8
9class Converter(nrd.md.Converter[nrd.html.HTMLRenderer]):
10 # actual renderer doesn't matter, we're just parsing.
11 def __init__(self, manpage_urls: dict[str, str]) -> None:
12 super().__init__()
13 self._renderer = nrd.html.HTMLRenderer(manpage_urls, {})
14
15def test_attr_span_parsing() -> None:
16 c = Converter({})
17 assert c._parse("[]{#test}") == [
18 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
19 content='', markup='', info='', meta={}, block=True, hidden=False),
20 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1, content='[]{#test}',
21 markup='', info='', meta={}, block=True, hidden=False,
22 children=[
23 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'test'}, map=None, level=0,
24 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
25 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
26 children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
27 ]),
28 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0,
29 children=None, content='', markup='', info='', meta={}, block=True, hidden=False)
30 ]
31 assert c._parse("[]{.test}") == [
32 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
33 content='', markup='', info='', meta={}, block=True, hidden=False),
34 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1, content='[]{.test}',
35 markup='', info='', meta={}, block=True, hidden=False,
36 children=[
37 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'class': 'test'}, map=None,
38 level=0, children=None, content='', markup='', info='', meta={}, block=False,
39 hidden=False),
40 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
41 children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
42 ]),
43 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0,
44 children=None, content='', markup='', info='', meta={}, block=True, hidden=False)
45 ]
46 assert c._parse("[]{.test1 .test2 #foo .test3 .test4}") == [
47 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
48 content='', markup='', info='', meta={}, block=True, hidden=False),
49 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
50 content='[]{.test1 .test2 #foo .test3 .test4}',
51 markup='', info='', meta={}, block=True, hidden=False,
52 children=[
53 Token(type='attr_span_begin', tag='span', nesting=1,
54 attrs={'class': 'test1 test2 test3 test4', 'id': 'foo'}, map=None, level=0,
55 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
56 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
57 children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
58 ]),
59 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0,
60 children=None, content='', markup='', info='', meta={}, block=True, hidden=False)
61 ]
62 assert c._parse("[]{#a #a}") == [
63 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
64 content='', markup='', info='', meta={}, block=True, hidden=False),
65 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
66 content='[]{#a #a}', markup='', info='', meta={}, block=True, hidden=False,
67 children=[
68 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
69 content='[]{#a #a}', markup='', info='', meta={}, block=False, hidden=False)
70 ]),
71 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
72 content='', markup='', info='', meta={}, block=True, hidden=False)
73 ]
74 assert c._parse("[]{foo}") == [
75 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
76 content='', markup='', info='', meta={}, block=True, hidden=False),
77 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
78 content='[]{foo}', markup='', info='', meta={}, block=True, hidden=False,
79 children=[
80 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
81 content='[]{foo}', markup='', info='', meta={}, block=False, hidden=False)
82 ]),
83 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
84 content='', markup='', info='', meta={}, block=True, hidden=False)
85 ]
86
87def test_attr_span_formatted() -> None:
88 c = Converter({})
89 assert c._parse("a[b c `d` ***e***]{#test}f") == [
90 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0,
91 children=None, content='', markup='', info='', meta={}, block=True, hidden=False),
92 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
93 content='a[b c `d` ***e***]{#test}f', markup='', info='', meta={}, block=True, hidden=False,
94 children=[
95 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0,
96 children=None, content='a', markup='', info='', meta={}, block=False, hidden=False),
97 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'test'}, map=None, level=0,
98 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
99 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
100 content='b c ', markup='', info='', meta={}, block=False, hidden=False),
101 Token(type='code_inline', tag='code', nesting=0, attrs={}, map=None, level=1,
102 children=None, content='d', markup='`', info='', meta={}, block=False, hidden=False),
103 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
104 content=' ', markup='', info='', meta={}, block=False, hidden=False),
105 Token(type='em_open', tag='em', nesting=1, attrs={}, map=None, level=1, children=None,
106 content='', markup='*', info='', meta={}, block=False, hidden=False),
107 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
108 content='', markup='', info='', meta={}, block=False, hidden=False),
109 Token(type='strong_open', tag='strong', nesting=1, attrs={}, map=None, level=2,
110 children=None, content='', markup='**', info='', meta={}, block=False, hidden=False),
111 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=3, children=None,
112 content='e', markup='', info='', meta={}, block=False, hidden=False),
113 Token(type='strong_close', tag='strong', nesting=-1, attrs={}, map=None, level=2,
114 children=None, content='', markup='**', info='', meta={}, block=False, hidden=False),
115 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
116 content='', markup='', info='', meta={}, block=False, hidden=False),
117 Token(type='em_close', tag='em', nesting=-1, attrs={}, map=None, level=1, children=None,
118 content='', markup='*', info='', meta={}, block=False, hidden=False),
119 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
120 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
121 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
122 content='f', markup='', info='', meta={}, block=False, hidden=False)
123 ]),
124 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
125 content='', markup='', info='', meta={}, block=True, hidden=False)
126 ]
127
128def test_attr_span_in_heading() -> None:
129 c = Converter({})
130 # inline anchors in headers are allowed, but header attributes should be preferred
131 assert c._parse("# foo []{#bar} baz") == [
132 Token(type='heading_open', tag='h1', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
133 content='', markup='#', info='', meta={}, block=True, hidden=False),
134 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
135 content='foo []{#bar} baz', markup='', info='', meta={}, block=True, hidden=False,
136 children=[
137 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
138 content='foo ', markup='', info='', meta={}, block=False, hidden=False),
139 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'bar'}, map=None, level=0,
140 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
141 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
142 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
143 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
144 content=' baz', markup='', info='', meta={}, block=False, hidden=False)
145 ]),
146 Token(type='heading_close', tag='h1', nesting=-1, attrs={}, map=None, level=0, children=None,
147 content='', markup='#', info='', meta={}, block=True, hidden=False)
148 ]
149
150def test_attr_span_on_links() -> None:
151 c = Converter({})
152 assert c._parse("[ [a](#bar) ]{#foo}") == [
153 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
154 content='', markup='', info='', meta={}, block=True, hidden=False),
155 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1, content='[ [a](#bar) ]{#foo}',
156 markup='', info='', meta={}, block=True, hidden=False,
157 children=[
158 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'foo'}, map=None, level=0,
159 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
160 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
161 content=' ', markup='', info='', meta={}, block=False, hidden=False),
162 Token(type='link_open', tag='a', nesting=1, attrs={'href': '#bar'}, map=None, level=1,
163 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
164 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
165 content='a', markup='', info='', meta={}, block=False, hidden=False),
166 Token(type='link_close', tag='a', nesting=-1, attrs={}, map=None, level=1, children=None,
167 content='', markup='', info='', meta={}, block=False, hidden=False),
168 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
169 content=' ', markup='', info='', meta={}, block=False, hidden=False),
170 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
171 children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
172 ]),
173 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
174 content='', markup='', info='', meta={}, block=True, hidden=False)
175 ]
176
177def test_attr_span_nested() -> None:
178 # inline anchors may contain more anchors (even though this is a bit pointless)
179 c = Converter({})
180 assert c._parse("[ [a]{#bar} ]{#foo}") == [
181 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
182 content='', markup='', info='', meta={}, block=True, hidden=False),
183 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
184 content='[ [a]{#bar} ]{#foo}', markup='', info='', meta={}, block=True, hidden=False,
185 children=[
186 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'foo'}, map=None, level=0,
187 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
188 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
189 content=' ', markup='', info='', meta={}, block=False, hidden=False),
190 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'bar'}, map=None, level=1,
191 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
192 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
193 content='a', markup='', info='', meta={}, block=False, hidden=False),
194 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=1,
195 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
196 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
197 content=' ', markup='', info='', meta={}, block=False, hidden=False),
198 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
199 children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
200 ]),
201 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
202 content='', markup='', info='', meta={}, block=True, hidden=False)
203 ]
204
205def test_attr_span_escaping() -> None:
206 c = Converter({})
207 assert c._parse("\\[a]{#bar}") == [
208 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
209 content='', markup='', info='', meta={}, block=True, hidden=False),
210 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
211 content='\\[a]{#bar}', markup='', info='', meta={}, block=True, hidden=False,
212 children=[
213 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
214 content='[a]{#bar}', markup='\\[', info='escape', meta={}, block=False, hidden=False)
215 ]),
216 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
217 content='', markup='', info='', meta={}, block=True, hidden=False)
218 ]
219 assert c._parse("\\\\[a]{#bar}") == [
220 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
221 content='', markup='', info='', meta={}, block=True, hidden=False),
222 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
223 content='\\\\[a]{#bar}', markup='', info='', meta={}, block=True, hidden=False,
224 children=[
225 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
226 content='\\', markup='\\\\', info='escape', meta={}, block=False, hidden=False),
227 Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'bar'}, map=None, level=0,
228 children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
229 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
230 content='a', markup='', info='', meta={}, block=False, hidden=False),
231 Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
232 children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
233 ]),
234 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
235 content='', markup='', info='', meta={}, block=True, hidden=False)
236 ]
237 assert c._parse("\\\\\\[a]{#bar}") == [
238 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
239 content='', markup='', info='', meta={}, block=True, hidden=False),
240 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
241 children=[
242 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
243 content='\\[a]{#bar}', markup='\\\\', info='escape', meta={}, block=False, hidden=False)
244 ],
245 content='\\\\\\[a]{#bar}', markup='', info='', meta={}, block=True, hidden=False),
246 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
247 content='', markup='', info='', meta={}, block=True, hidden=False)
248 ]
249
250def test_inline_comment_basic() -> None:
251 c = Converter({})
252 assert c._parse("a <!-- foo --><!----> b") == [
253 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
254 content='', markup='', info='', meta={}, block=True, hidden=False),
255 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
256 content='a <!-- foo --><!----> b', markup='', info='', meta={}, block=True, hidden=False,
257 children=[
258 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
259 content='a b', markup='', info='', meta={}, block=False, hidden=False)
260 ]),
261 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
262 content='', markup='', info='', meta={}, block=True, hidden=False)
263 ]
264 assert c._parse("a<!-- b -->") == [
265 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
266 content='', markup='', info='', meta={}, block=True, hidden=False),
267 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
268 content='a<!-- b -->', markup='', info='', meta={}, block=True, hidden=False,
269 children=[
270 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
271 content='a', markup='', info='', meta={}, block=False, hidden=False)
272 ]),
273 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
274 content='', markup='', info='', meta={}, block=True, hidden=False)
275 ]
276
277def test_inline_comment_does_not_nest_in_code() -> None:
278 c = Converter({})
279 assert c._parse("`a<!-- b -->c`") == [
280 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
281 content='', markup='', info='', meta={}, block=True, hidden=False),
282 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
283 content='`a<!-- b -->c`', markup='', info='', meta={}, block=True, hidden=False,
284 children=[
285 Token(type='code_inline', tag='code', nesting=0, attrs={}, map=None, level=0, children=None,
286 content='a<!-- b -->c', markup='`', info='', meta={}, block=False, hidden=False)
287 ]),
288 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
289 content='', markup='', info='', meta={}, block=True, hidden=False)
290 ]
291
292def test_inline_comment_does_not_nest_elsewhere() -> None:
293 c = Converter({})
294 assert c._parse("*a<!-- b -->c*") == [
295 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
296 content='', markup='', info='', meta={}, block=True, hidden=False),
297 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
298 content='*a<!-- b -->c*', markup='', info='', meta={}, block=True, hidden=False,
299 children=[
300 Token(type='em_open', tag='em', nesting=1, attrs={}, map=None, level=0, children=None,
301 content='', markup='*', info='', meta={}, block=False, hidden=False),
302 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
303 content='ac', markup='', info='', meta={}, block=False, hidden=False),
304 Token(type='em_close', tag='em', nesting=-1, attrs={}, map=None, level=0, children=None,
305 content='', markup='*', info='', meta={}, block=False, hidden=False)
306 ]),
307 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
308 content='', markup='', info='', meta={}, block=True, hidden=False)
309 ]
310
311def test_inline_comment_can_be_escaped() -> None:
312 c = Converter({})
313 assert c._parse("a\\<!-- b -->c") == [
314 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
315 content='', markup='', info='', meta={}, block=True, hidden=False),
316 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
317 content='a\\<!-- b -->c', markup='', info='', meta={}, block=True, hidden=False,
318 children=[
319 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
320 content='a<!-- b -->c', markup='', info='', meta={}, block=False, hidden=False)
321 ]),
322 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
323 content='', markup='', info='', meta={}, block=True, hidden=False)
324 ]
325 assert c._parse("a\\\\<!-- b -->c") == [
326 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
327 content='', markup='', info='', meta={}, block=True, hidden=False),
328 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
329 children=[
330 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
331 content='a\\c', markup='', info='', meta={}, block=False, hidden=False)
332 ],
333 content='a\\\\<!-- b -->c', markup='', info='', meta={}, block=True, hidden=False),
334 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
335 content='', markup='', info='', meta={}, block=True, hidden=False)
336 ]
337 assert c._parse("a\\\\\\<!-- b -->c") == [
338 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
339 content='', markup='', info='', meta={}, block=True, hidden=False),
340 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
341 children=[
342 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
343 content='a\\<!-- b -->c', markup='', info='', meta={}, block=False, hidden=False)
344 ],
345 content='a\\\\\\<!-- b -->c', markup='', info='', meta={}, block=True, hidden=False),
346 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
347 content='', markup='', info='', meta={}, block=True, hidden=False)
348 ]
349
350def test_block_comment() -> None:
351 c = Converter({})
352 assert c._parse("<!-- a -->") == []
353 assert c._parse("<!-- a\n-->") == []
354 assert c._parse("<!--\na\n-->") == []
355 assert c._parse("<!--\n\na\n\n-->") == []
356 assert c._parse("<!--\n\n```\n\n\n```\n\n-->") == []
357
358def test_heading_attributes() -> None:
359 c = Converter({})
360 assert c._parse("# foo *bar* {#hid}") == [
361 Token(type='heading_open', tag='h1', nesting=1, attrs={'id': 'hid'}, map=[0, 1], level=0,
362 children=None, content='', markup='#', info='', meta={}, block=True, hidden=False),
363 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
364 content='foo *bar* {#hid}', markup='', info='', meta={}, block=True, hidden=False,
365 children=[
366 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
367 content='foo ', markup='', info='', meta={}, block=False, hidden=False),
368 Token(type='em_open', tag='em', nesting=1, attrs={}, map=None, level=0, children=None,
369 content='', markup='*', info='', meta={}, block=False, hidden=False),
370 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
371 content='bar', markup='', info='', meta={}, block=False, hidden=False),
372 Token(type='em_close', tag='em', nesting=-1, attrs={}, map=None, level=0, children=None,
373 content='', markup='*', info='', meta={}, block=False, hidden=False),
374 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
375 content='', markup='', info='', meta={}, block=False, hidden=False)
376 ]),
377 Token(type='heading_close', tag='h1', nesting=-1, attrs={}, map=None, level=0, children=None,
378 content='', markup='#', info='', meta={}, block=True, hidden=False)
379 ]
380 assert c._parse("# foo--bar {#id-with--double-dashes}") == [
381 Token(type='heading_open', tag='h1', nesting=1, attrs={'id': 'id-with--double-dashes'}, map=[0, 1],
382 level=0, children=None, content='', markup='#', info='', meta={}, block=True, hidden=False),
383 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
384 content='foo--bar {#id-with--double-dashes}', markup='', info='', meta={}, block=True,
385 hidden=False,
386 children=[
387 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
388 content='foo–bar', markup='', info='', meta={}, block=False, hidden=False)
389 ]),
390 Token(type='heading_close', tag='h1', nesting=-1, attrs={}, map=None, level=0, children=None,
391 content='', markup='#', info='', meta={}, block=True, hidden=False)
392 ]
393
394def test_admonitions() -> None:
395 c = Converter({})
396 assert c._parse("::: {.note}") == [
397 Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
398 children=None, content='', markup=':::', info=' {.note}', meta={'kind': 'note'}, block=True,
399 hidden=False),
400 Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
401 children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
402 ]
403 assert c._parse("::: {.caution}") == [
404 Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
405 children=None, content='', markup=':::', info=' {.caution}', meta={'kind': 'caution'},
406 block=True, hidden=False),
407 Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
408 children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
409 ]
410 assert c._parse("::: {.tip}") == [
411 Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
412 children=None, content='', markup=':::', info=' {.tip}', meta={'kind': 'tip'}, block=True,
413 hidden=False),
414 Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
415 children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
416 ]
417 assert c._parse("::: {.important}") == [
418 Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
419 children=None, content='', markup=':::', info=' {.important}', meta={'kind': 'important'},
420 block=True, hidden=False),
421 Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
422 children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
423 ]
424 assert c._parse("::: {.warning}") == [
425 Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
426 children=None, content='', markup=':::', info=' {.warning}', meta={'kind': 'warning'},
427 block=True, hidden=False),
428 Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
429 children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
430 ]
431
432def test_example() -> None:
433 c = Converter({})
434 assert c._parse("::: {.example}\n# foo") == [
435 Token(type='example_open', tag='div', nesting=1, attrs={}, map=[0, 2], level=0, children=None,
436 content='', markup=':::', info=' {.example}', meta={}, block=True, hidden=False),
437 Token(type='example_title_open', tag='h1', nesting=1, attrs={}, map=[1, 2], level=1, children=None,
438 content='', markup='#', info='', meta={}, block=True, hidden=False),
439 Token(type='inline', tag='', nesting=0, attrs={}, map=[1, 2], level=2,
440 content='foo', markup='', info='', meta={}, block=True, hidden=False,
441 children=[
442 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
443 content='foo', markup='', info='', meta={}, block=False, hidden=False)
444 ]),
445 Token(type='example_title_close', tag='h1', nesting=-1, attrs={}, map=None, level=1, children=None,
446 content='', markup='#', info='', meta={}, block=True, hidden=False),
447 Token(type='example_close', tag='div', nesting=-1, attrs={}, map=None, level=0, children=None,
448 content='', markup='', info='', meta={}, block=True, hidden=False)
449 ]
450 assert c._parse("::: {#eid .example}\n# foo") == [
451 Token(type='example_open', tag='div', nesting=1, attrs={'id': 'eid'}, map=[0, 2], level=0,
452 children=None, content='', markup=':::', info=' {#eid .example}', meta={}, block=True,
453 hidden=False),
454 Token(type='example_title_open', tag='h1', nesting=1, attrs={}, map=[1, 2], level=1, children=None,
455 content='', markup='#', info='', meta={}, block=True, hidden=False),
456 Token(type='inline', tag='', nesting=0, attrs={}, map=[1, 2], level=2,
457 content='foo', markup='', info='', meta={}, block=True, hidden=False,
458 children=[
459 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
460 content='foo', markup='', info='', meta={}, block=False, hidden=False)
461 ]),
462 Token(type='example_title_close', tag='h1', nesting=-1, attrs={}, map=None, level=1, children=None,
463 content='', markup='#', info='', meta={}, block=True, hidden=False),
464 Token(type='example_close', tag='div', nesting=-1, attrs={}, map=None, level=0, children=None,
465 content='', markup='', info='', meta={}, block=True, hidden=False)
466 ]
467 assert c._parse("::: {.example .note}") == [
468 Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
469 content='', markup='', info='', meta={}, block=True, hidden=False),
470 Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
471 content='::: {.example .note}', markup='', info='', meta={}, block=True, hidden=False,
472 children=[
473 Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
474 content='::: {.example .note}', markup='', info='', meta={}, block=False, hidden=False)
475 ]),
476 Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
477 content='', markup='', info='', meta={}, block=True, hidden=False)
478 ]
479 assert c._parse("::: {.example}\n### foo: `code`\nbar\n:::\nbaz") == [
480 Token(type='example_open', tag='div', nesting=1, map=[0, 3], markup=':::', info=' {.example}',
481 block=True),
482 Token(type='example_title_open', tag='h3', nesting=1, map=[1, 2], level=1, markup='###', block=True),
483 Token(type='inline', tag='', nesting=0, map=[1, 2], level=2, content='foo: `code`', block=True,
484 children=[
485 Token(type='text', tag='', nesting=0, content='foo: '),
486 Token(type='code_inline', tag='code', nesting=0, content='code', markup='`')
487 ]),
488 Token(type='example_title_close', tag='h3', nesting=-1, level=1, markup='###', block=True),
489 Token(type='paragraph_open', tag='p', nesting=1, map=[2, 3], level=1, block=True),
490 Token(type='inline', tag='', nesting=0, map=[2, 3], level=2, content='bar', block=True,
491 children=[
492 Token(type='text', tag='', nesting=0, content='bar')
493 ]),
494 Token(type='paragraph_close', tag='p', nesting=-1, level=1, block=True),
495 Token(type='example_close', tag='div', nesting=-1, markup=':::', block=True),
496 Token(type='paragraph_open', tag='p', nesting=1, map=[4, 5], block=True),
497 Token(type='inline', tag='', nesting=0, map=[4, 5], level=1, content='baz', block=True,
498 children=[
499 Token(type='text', tag='', nesting=0, content='baz')
500 ]),
501 Token(type='paragraph_close', tag='p', nesting=-1, block=True)
502 ]
503
504 with pytest.raises(SrcError) as exc:
505 c._parse("::: {.example}\n### foo\n### bar\n:::")
506
507 assert str(exc.value) == textwrap.dedent(
508 """
509 unexpected non-title heading in `:::{.example}`; are you missing a `:::`?
510 Note: blocks like `:::{.example}` are only allowed to contain a single heading in order to simplify TOC generation.
511
512 \x1b[33m`:::{.example}` block at lines 1-3:\x1b[0m
513 \x1b[2m\x1b[37m 1\x1b[0m \x1b[1m\x1b[33m┃\x1b[0m ::: {.example}\x1b[0m
514 \x1b[2m\x1b[37m 2\x1b[0m \x1b[1m\x1b[33m┃\x1b[0m ### foo\x1b[0m
515 \x1b[2m\x1b[37m 3\x1b[0m \x1b[1m\x1b[33m┃\x1b[0m ### bar\x1b[0m
516 \x1b[2m\x1b[37m 4\x1b[0m \x1b[2m\x1b[37m┆ :::\x1b[0m
517
518 \x1b[33mUnexpected heading at line 3:\x1b[0m
519 \x1b[2m\x1b[37m 1\x1b[0m \x1b[2m\x1b[37m┆ ::: {.example}\x1b[0m
520 \x1b[2m\x1b[37m 2\x1b[0m \x1b[2m\x1b[37m┆ ### foo\x1b[0m
521 \x1b[2m\x1b[37m 3\x1b[0m \x1b[1m\x1b[33m┃\x1b[0m ### bar\x1b[0m
522 \x1b[2m\x1b[37m 4\x1b[0m \x1b[2m\x1b[37m┆ :::\x1b[0m
523 """
524 ).strip()
525
526def test_footnotes() -> None:
527 c = Converter({})
528 assert c._parse("text [^foo]\n\n[^foo]: bar") == [
529 Token(type='paragraph_open', tag='p', nesting=1, map=[0, 1], block=True),
530 Token(type='inline', tag='', nesting=0, map=[0, 1], level=1, content='text [^foo]', block=True,
531 children=[
532 Token(type='text', tag='', nesting=0, content='text '),
533 Token(type='footnote_ref', tag='', nesting=0, attrs={'id': 'foo.__back.0'},
534 meta={'id': 0, 'subId': 0, 'label': 'foo', 'target': 'foo'})
535 ]),
536 Token(type='paragraph_close', tag='p', nesting=-1, block=True),
537 Token(type='footnote_block_open', tag='', nesting=1),
538 Token(type='footnote_open', tag='', nesting=1, attrs={'id': 'foo'}, meta={'id': 0, 'label': 'foo'}),
539 Token(type='paragraph_open', tag='p', nesting=1, map=[2, 3], level=1, block=True, hidden=False),
540 Token(type='inline', tag='', nesting=0, map=[2, 3], level=2, content='bar', block=True,
541 children=[
542 Token(type='text', tag='', nesting=0, content='bar')
543 ]),
544 Token(type='footnote_anchor', tag='', nesting=0,
545 meta={'id': 0, 'label': 'foo', 'subId': 0, 'target': 'foo.__back.0'}),
546 Token(type='paragraph_close', tag='p', nesting=-1, level=1, block=True),
547 Token(type='footnote_close', tag='', nesting=-1),
548 Token(type='footnote_block_close', tag='', nesting=-1),
549 ]