docspan 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docspan/__init__.py +3 -0
- docspan/__main__.py +0 -0
- docspan/backends/__init__.py +19 -0
- docspan/backends/base.py +85 -0
- docspan/backends/confluence/__init__.py +0 -0
- docspan/backends/confluence/adf/__init__.py +14 -0
- docspan/backends/confluence/adf/comparator.py +427 -0
- docspan/backends/confluence/adf/converter.py +119 -0
- docspan/backends/confluence/adf/converters.py +1449 -0
- docspan/backends/confluence/adf/interfaces.py +191 -0
- docspan/backends/confluence/adf/nodes.py +2085 -0
- docspan/backends/confluence/adf/parser.py +400 -0
- docspan/backends/confluence/adf/validators.py +161 -0
- docspan/backends/confluence/adf/visitors.py +495 -0
- docspan/backends/confluence/backend.py +227 -0
- docspan/backends/confluence/client.py +44 -0
- docspan/backends/confluence/config/__init__.py +21 -0
- docspan/backends/confluence/config/loader.py +107 -0
- docspan/backends/confluence/config/models.py +167 -0
- docspan/backends/confluence/config/validation.py +297 -0
- docspan/backends/confluence/markdown/__init__.py +22 -0
- docspan/backends/confluence/markdown/ast.py +819 -0
- docspan/backends/confluence/markdown/extensions/__init__.py +5 -0
- docspan/backends/confluence/markdown/extensions/frontmatter.py +80 -0
- docspan/backends/confluence/markdown/extensions/mermaid.py +64 -0
- docspan/backends/confluence/markdown/extensions/wikilinks.py +179 -0
- docspan/backends/confluence/markdown/inline_parser.py +495 -0
- docspan/backends/confluence/markdown/parser.py +1006 -0
- docspan/backends/confluence/models/__init__.py +18 -0
- docspan/backends/confluence/models/markdown_file.py +402 -0
- docspan/backends/confluence/models/page.py +212 -0
- docspan/backends/confluence/models/path_utils.py +34 -0
- docspan/backends/confluence/models/results.py +28 -0
- docspan/backends/confluence/models/sync_status.py +382 -0
- docspan/backends/confluence/services/__init__.py +0 -0
- docspan/backends/confluence/services/confluence/__init__.py +40 -0
- docspan/backends/confluence/services/confluence/attachment_client.py +147 -0
- docspan/backends/confluence/services/confluence/base_client.py +420 -0
- docspan/backends/confluence/services/confluence/client.py +376 -0
- docspan/backends/confluence/services/confluence/comment_client.py +682 -0
- docspan/backends/confluence/services/confluence/crawler.py +587 -0
- docspan/backends/confluence/services/confluence/label_client.py +130 -0
- docspan/backends/confluence/services/confluence/page_client.py +1288 -0
- docspan/backends/confluence/services/confluence/space_client.py +179 -0
- docspan/backends/confluence/services/confluence/url_parser.py +106 -0
- docspan/backends/google_docs/__init__.py +0 -0
- docspan/backends/google_docs/auth.py +143 -0
- docspan/backends/google_docs/backend.py +140 -0
- docspan/backends/google_docs/client.py +665 -0
- docspan/backends/google_docs/converter.py +471 -0
- docspan/backends/google_docs/docs_request_builder.py +232 -0
- docspan/backends/google_docs/docs_structure_parser.py +120 -0
- docspan/backends/google_docs/markdown_to_paragraph_parser.py +145 -0
- docspan/cli/__init__.py +0 -0
- docspan/cli/main.py +408 -0
- docspan/config.py +62 -0
- docspan/core/__init__.py +49 -0
- docspan/core/merge.py +30 -0
- docspan/core/orchestrator.py +332 -0
- docspan/core/paths.py +8 -0
- docspan/core/state.py +53 -0
- docspan-0.1.0.dist-info/METADATA +273 -0
- docspan-0.1.0.dist-info/RECORD +65 -0
- docspan-0.1.0.dist-info/WHEEL +4 -0
- docspan-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstract Syntax Tree nodes for Markdown parsing.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class MarkdownNode:
|
|
11
|
+
"""
|
|
12
|
+
Base class for nodes in the Markdown Abstract Syntax Tree (AST).
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
type: Node type
|
|
16
|
+
content: Optional raw content
|
|
17
|
+
children: List of child nodes
|
|
18
|
+
attrs: Additional attributes
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
type: str = ""
|
|
22
|
+
content: Optional[str] = None
|
|
23
|
+
children: List["MarkdownNode"] = field(default_factory=list)
|
|
24
|
+
attrs: Dict[str, Any] = field(default_factory=dict)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class TextNode(MarkdownNode):
|
|
29
|
+
"""
|
|
30
|
+
Node for plain text.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
content: Text content
|
|
34
|
+
marks: Text formatting marks (bold, italic, etc.)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
marks: List[Dict[str, Any]] = field(default_factory=list)
|
|
38
|
+
|
|
39
|
+
def __post_init__(self) -> None:
|
|
40
|
+
"""Initialize type."""
|
|
41
|
+
self.type = "text"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class HeadingNode(MarkdownNode):
|
|
46
|
+
"""
|
|
47
|
+
Node for headings.
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
level: Heading level (1-6)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
level: int = 1
|
|
54
|
+
|
|
55
|
+
def __post_init__(self) -> None:
|
|
56
|
+
"""Initialize type."""
|
|
57
|
+
self.type = "heading"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class ParagraphNode(MarkdownNode):
|
|
62
|
+
"""Node for paragraphs."""
|
|
63
|
+
|
|
64
|
+
def __post_init__(self) -> None:
|
|
65
|
+
"""Initialize type."""
|
|
66
|
+
self.type = "paragraph"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class ListItemNode(MarkdownNode):
|
|
71
|
+
"""
|
|
72
|
+
Node for list items.
|
|
73
|
+
|
|
74
|
+
Attributes:
|
|
75
|
+
bullet: Bullet character or number
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
bullet: str = "*"
|
|
79
|
+
|
|
80
|
+
def __post_init__(self) -> None:
|
|
81
|
+
"""Initialize type."""
|
|
82
|
+
self.type = "listItem"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class BulletListNode(MarkdownNode):
|
|
87
|
+
"""Node for bullet lists."""
|
|
88
|
+
|
|
89
|
+
def __post_init__(self) -> None:
|
|
90
|
+
"""Initialize type."""
|
|
91
|
+
self.type = "bulletList"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclass
|
|
95
|
+
class OrderedListNode(MarkdownNode):
|
|
96
|
+
"""Node for ordered lists."""
|
|
97
|
+
|
|
98
|
+
def __post_init__(self) -> None:
|
|
99
|
+
"""Initialize type."""
|
|
100
|
+
self.type = "orderedList"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class CodeBlockNode(MarkdownNode):
|
|
105
|
+
"""
|
|
106
|
+
Node for code blocks.
|
|
107
|
+
|
|
108
|
+
Attributes:
|
|
109
|
+
language: Programming language for syntax highlighting
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
language: Optional[str] = None
|
|
113
|
+
|
|
114
|
+
def __post_init__(self) -> None:
|
|
115
|
+
"""Initialize type."""
|
|
116
|
+
self.type = "codeBlock"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass
|
|
120
|
+
class InlineCodeNode(MarkdownNode):
|
|
121
|
+
"""Node for inline code."""
|
|
122
|
+
|
|
123
|
+
def __post_init__(self) -> None:
|
|
124
|
+
"""Initialize type."""
|
|
125
|
+
self.type = "inlineCode"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class BlockquoteNode(MarkdownNode):
|
|
130
|
+
"""Node for blockquotes."""
|
|
131
|
+
|
|
132
|
+
def __post_init__(self) -> None:
|
|
133
|
+
"""Initialize type."""
|
|
134
|
+
self.type = "blockquote"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass
|
|
138
|
+
class TableNode(MarkdownNode):
|
|
139
|
+
"""
|
|
140
|
+
Node for tables.
|
|
141
|
+
|
|
142
|
+
Attributes:
|
|
143
|
+
headers: Table headers
|
|
144
|
+
rows: Table rows
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
headers: List[str] = field(default_factory=list)
|
|
148
|
+
rows: List[List[MarkdownNode]] = field(default_factory=list)
|
|
149
|
+
|
|
150
|
+
def __post_init__(self) -> None:
|
|
151
|
+
"""Initialize type."""
|
|
152
|
+
self.type = "table"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@dataclass
|
|
156
|
+
class LinkNode(MarkdownNode):
|
|
157
|
+
"""
|
|
158
|
+
Node for links.
|
|
159
|
+
|
|
160
|
+
Attributes:
|
|
161
|
+
url: Link URL
|
|
162
|
+
title: Link title
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
url: str = ""
|
|
166
|
+
title: Optional[str] = None
|
|
167
|
+
|
|
168
|
+
def __post_init__(self) -> None:
|
|
169
|
+
"""Initialize type."""
|
|
170
|
+
self.type = "link"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@dataclass
|
|
174
|
+
class ImageNode(MarkdownNode):
|
|
175
|
+
"""
|
|
176
|
+
Node for images.
|
|
177
|
+
|
|
178
|
+
Attributes:
|
|
179
|
+
src: Image source URL or Confluence file ID
|
|
180
|
+
alt: Alternative text
|
|
181
|
+
title: Image title
|
|
182
|
+
width: Image width (pixels or percentage)
|
|
183
|
+
height: Image height (pixels)
|
|
184
|
+
layout: Layout option (center, wide, full-width, wrap-left, wrap-right)
|
|
185
|
+
is_confluence_attachment: True if using Confluence file ID instead of external URL
|
|
186
|
+
collection: Confluence Media Services collection name (for Confluence attachments)
|
|
187
|
+
occurrence_key: Confluence occurrence key (for deletion support)
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
src: str = ""
|
|
191
|
+
alt: str = ""
|
|
192
|
+
title: Optional[str] = None
|
|
193
|
+
width: Optional[int] = None
|
|
194
|
+
height: Optional[int] = None
|
|
195
|
+
layout: Optional[str] = None # center, wide, full-width, wrap-left, wrap-right
|
|
196
|
+
is_confluence_attachment: bool = False
|
|
197
|
+
collection: Optional[str] = None
|
|
198
|
+
occurrence_key: Optional[str] = None
|
|
199
|
+
|
|
200
|
+
def __post_init__(self) -> None:
|
|
201
|
+
"""Initialize type."""
|
|
202
|
+
self.type = "image"
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@dataclass
|
|
206
|
+
class MediaGroupNode(MarkdownNode):
|
|
207
|
+
"""
|
|
208
|
+
Node for media groups (image galleries).
|
|
209
|
+
|
|
210
|
+
A container for multiple media items displayed together, commonly used
|
|
211
|
+
for image galleries or multiple file attachments.
|
|
212
|
+
|
|
213
|
+
Attributes:
|
|
214
|
+
children: List of ImageNode items in the group
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
def __post_init__(self) -> None:
|
|
218
|
+
"""Initialize type."""
|
|
219
|
+
self.type = "mediaGroup"
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@dataclass
|
|
223
|
+
class WikiLinkNode(MarkdownNode):
|
|
224
|
+
"""
|
|
225
|
+
Node for wiki-style links ([[page]] or [[page|title]]).
|
|
226
|
+
|
|
227
|
+
Attributes:
|
|
228
|
+
target: Link target (page name)
|
|
229
|
+
display: Display text
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
target: str = ""
|
|
233
|
+
display: Optional[str] = None
|
|
234
|
+
|
|
235
|
+
def __post_init__(self) -> None:
|
|
236
|
+
"""Initialize type."""
|
|
237
|
+
self.type = "wikiLink"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@dataclass
|
|
241
|
+
class MentionNode(MarkdownNode):
|
|
242
|
+
"""
|
|
243
|
+
Node for user mentions (@username).
|
|
244
|
+
|
|
245
|
+
Attributes:
|
|
246
|
+
username: Username being mentioned (without @ prefix)
|
|
247
|
+
user_id: Confluence user ID (optional, resolved during conversion)
|
|
248
|
+
text: Display text for the mention (defaults to @username)
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
username: str = ""
|
|
252
|
+
user_id: Optional[str] = None
|
|
253
|
+
text: Optional[str] = None
|
|
254
|
+
|
|
255
|
+
def __post_init__(self) -> None:
|
|
256
|
+
"""Initialize type."""
|
|
257
|
+
self.type = "mention"
|
|
258
|
+
# Set default text if not provided
|
|
259
|
+
if not self.text and self.username:
|
|
260
|
+
self.text = f"@{self.username}"
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@dataclass
|
|
264
|
+
class EmojiNode(MarkdownNode):
|
|
265
|
+
"""
|
|
266
|
+
Node for emoji expressions (:emoji_name:).
|
|
267
|
+
|
|
268
|
+
Attributes:
|
|
269
|
+
short_name: Emoji short name (e.g., "smile", "tada", "rocket")
|
|
270
|
+
emoji_id: Confluence emoji ID (optional, resolved during conversion)
|
|
271
|
+
text: Fallback text representation (defaults to :short_name:)
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
short_name: str = ""
|
|
275
|
+
emoji_id: Optional[str] = None
|
|
276
|
+
text: Optional[str] = None
|
|
277
|
+
|
|
278
|
+
def __post_init__(self) -> None:
|
|
279
|
+
"""Initialize type."""
|
|
280
|
+
self.type = "emoji"
|
|
281
|
+
# Set default text if not provided
|
|
282
|
+
if not self.text and self.short_name:
|
|
283
|
+
self.text = f":{self.short_name}:"
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@dataclass
|
|
287
|
+
class ExpandNode(MarkdownNode):
|
|
288
|
+
"""
|
|
289
|
+
Node for collapsible/expandable sections.
|
|
290
|
+
|
|
291
|
+
Converts HTML <details><summary> tags to Confluence expand nodes.
|
|
292
|
+
|
|
293
|
+
Attributes:
|
|
294
|
+
title: Title shown in the expand header (from <summary> tag)
|
|
295
|
+
children: Child nodes contained within the expand section
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
title: str = ""
|
|
299
|
+
|
|
300
|
+
def __post_init__(self) -> None:
|
|
301
|
+
"""Initialize type."""
|
|
302
|
+
self.type = "expand"
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@dataclass
|
|
306
|
+
class HorizontalRuleNode(MarkdownNode):
|
|
307
|
+
"""Node for horizontal rules."""
|
|
308
|
+
|
|
309
|
+
def __post_init__(self) -> None:
|
|
310
|
+
"""Initialize type."""
|
|
311
|
+
self.type = "horizontalRule"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
@dataclass
|
|
315
|
+
class MermaidNode(MarkdownNode):
|
|
316
|
+
"""
|
|
317
|
+
Node for Mermaid diagrams.
|
|
318
|
+
|
|
319
|
+
Attributes:
|
|
320
|
+
code: Mermaid diagram code
|
|
321
|
+
"""
|
|
322
|
+
|
|
323
|
+
code: str = ""
|
|
324
|
+
|
|
325
|
+
def __post_init__(self) -> None:
|
|
326
|
+
"""Initialize type."""
|
|
327
|
+
self.type = "mermaid"
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@dataclass
|
|
331
|
+
class TaskListNode(MarkdownNode):
|
|
332
|
+
"""
|
|
333
|
+
Node for task lists (checklists).
|
|
334
|
+
|
|
335
|
+
Converts GitHub-style task lists to Confluence task lists.
|
|
336
|
+
|
|
337
|
+
Attributes:
|
|
338
|
+
children: List of TaskItemNode items
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
def __post_init__(self) -> None:
|
|
342
|
+
"""Initialize type."""
|
|
343
|
+
self.type = "taskList"
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
@dataclass
|
|
347
|
+
class TaskItemNode(MarkdownNode):
|
|
348
|
+
"""
|
|
349
|
+
Node for individual task items in a task list.
|
|
350
|
+
|
|
351
|
+
Attributes:
|
|
352
|
+
checked: Whether the task is checked/completed
|
|
353
|
+
children: Content of the task item (typically paragraphs)
|
|
354
|
+
"""
|
|
355
|
+
|
|
356
|
+
checked: bool = False
|
|
357
|
+
|
|
358
|
+
def __post_init__(self) -> None:
|
|
359
|
+
"""Initialize type."""
|
|
360
|
+
self.type = "taskItem"
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@dataclass
|
|
364
|
+
class StatusBadgeNode(MarkdownNode):
|
|
365
|
+
"""
|
|
366
|
+
Node for status badges/lozenges.
|
|
367
|
+
|
|
368
|
+
Converts [!STATUS] syntax to Confluence status lozenges.
|
|
369
|
+
|
|
370
|
+
Attributes:
|
|
371
|
+
text: Status text (e.g., "DONE", "IN PROGRESS")
|
|
372
|
+
color: Status color (neutral, blue, green, yellow, red, purple)
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
text: str = ""
|
|
376
|
+
color: str = "neutral"
|
|
377
|
+
|
|
378
|
+
def __post_init__(self) -> None:
|
|
379
|
+
"""Initialize type."""
|
|
380
|
+
self.type = "statusBadge"
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
@dataclass
|
|
384
|
+
class DateNode(MarkdownNode):
|
|
385
|
+
"""
|
|
386
|
+
Node for date fields.
|
|
387
|
+
|
|
388
|
+
Converts ISO date strings to Confluence date nodes.
|
|
389
|
+
|
|
390
|
+
Attributes:
|
|
391
|
+
timestamp: Unix timestamp in milliseconds
|
|
392
|
+
date_string: Original date string (for display)
|
|
393
|
+
"""
|
|
394
|
+
|
|
395
|
+
timestamp: int = 0
|
|
396
|
+
date_string: str = ""
|
|
397
|
+
|
|
398
|
+
def __post_init__(self) -> None:
|
|
399
|
+
"""Initialize type."""
|
|
400
|
+
self.type = "date"
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
@dataclass
|
|
404
|
+
class LayoutSectionNode(MarkdownNode):
|
|
405
|
+
"""
|
|
406
|
+
Node for multi-column layout sections.
|
|
407
|
+
|
|
408
|
+
Converts ::: columns syntax to Confluence layout sections.
|
|
409
|
+
|
|
410
|
+
Attributes:
|
|
411
|
+
children: List of LayoutColumnNode items
|
|
412
|
+
"""
|
|
413
|
+
|
|
414
|
+
def __post_init__(self) -> None:
|
|
415
|
+
"""Initialize type."""
|
|
416
|
+
self.type = "layoutSection"
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
@dataclass
|
|
420
|
+
class LayoutColumnNode(MarkdownNode):
|
|
421
|
+
"""
|
|
422
|
+
Node for individual columns within a layout section.
|
|
423
|
+
|
|
424
|
+
Attributes:
|
|
425
|
+
width: Column width percentage (e.g., 50 for 50%)
|
|
426
|
+
children: Content within the column
|
|
427
|
+
"""
|
|
428
|
+
|
|
429
|
+
width: Optional[int] = None
|
|
430
|
+
|
|
431
|
+
def __post_init__(self) -> None:
|
|
432
|
+
"""Initialize type."""
|
|
433
|
+
self.type = "layoutColumn"
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
@dataclass
|
|
437
|
+
class HighlightedTextNode(MarkdownNode):
|
|
438
|
+
"""
|
|
439
|
+
Node for highlighted/marked text.
|
|
440
|
+
|
|
441
|
+
Converts ==text== syntax to highlighted text with background color.
|
|
442
|
+
|
|
443
|
+
Attributes:
|
|
444
|
+
content: Text content
|
|
445
|
+
bg_color: Background color (default: yellow #ffff00)
|
|
446
|
+
marks: Additional text formatting marks
|
|
447
|
+
"""
|
|
448
|
+
|
|
449
|
+
bg_color: str = "#ffff00"
|
|
450
|
+
marks: List[Dict[str, Any]] = field(default_factory=list)
|
|
451
|
+
|
|
452
|
+
def __post_init__(self) -> None:
|
|
453
|
+
"""Initialize type."""
|
|
454
|
+
self.type = "highlightedText"
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
@dataclass
|
|
458
|
+
class ColoredTextNode(MarkdownNode):
|
|
459
|
+
"""
|
|
460
|
+
Node for colored text.
|
|
461
|
+
|
|
462
|
+
Converts <mark style="color:..."> syntax to colored text.
|
|
463
|
+
|
|
464
|
+
Attributes:
|
|
465
|
+
content: Text content
|
|
466
|
+
color: Text color (hex code or CSS color name)
|
|
467
|
+
bg_color: Optional background color
|
|
468
|
+
marks: Additional text formatting marks
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
color: Optional[str] = None
|
|
472
|
+
bg_color: Optional[str] = None
|
|
473
|
+
marks: List[Dict[str, Any]] = field(default_factory=list)
|
|
474
|
+
|
|
475
|
+
def __post_init__(self) -> None:
|
|
476
|
+
"""Initialize type."""
|
|
477
|
+
self.type = "coloredText"
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
@dataclass
|
|
481
|
+
class URLEmbedNode(MarkdownNode):
|
|
482
|
+
"""
|
|
483
|
+
Node for embedded URLs (videos, rich content).
|
|
484
|
+
|
|
485
|
+
Auto-detects URLs and creates appropriate embed cards.
|
|
486
|
+
|
|
487
|
+
Attributes:
|
|
488
|
+
url: URL to embed
|
|
489
|
+
embed_type: Type of embed (video, card)
|
|
490
|
+
layout: Layout mode (center, wide, full-width)
|
|
491
|
+
width: Optional width in pixels
|
|
492
|
+
height: Optional height in pixels
|
|
493
|
+
"""
|
|
494
|
+
|
|
495
|
+
url: str = ""
|
|
496
|
+
embed_type: str = "card" # video, card
|
|
497
|
+
layout: str = "center"
|
|
498
|
+
width: Optional[int] = None
|
|
499
|
+
height: Optional[int] = None
|
|
500
|
+
|
|
501
|
+
def __post_init__(self) -> None:
|
|
502
|
+
"""Initialize type."""
|
|
503
|
+
self.type = "urlEmbed"
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
@dataclass
|
|
507
|
+
class ExtensionNode(MarkdownNode):
|
|
508
|
+
"""
|
|
509
|
+
Base class for Confluence macro/extension nodes.
|
|
510
|
+
|
|
511
|
+
Extensions represent Confluence-specific functionality that goes beyond
|
|
512
|
+
standard markdown, such as TOC, info panels, status lozenges, etc.
|
|
513
|
+
|
|
514
|
+
Attributes:
|
|
515
|
+
extension_key: Macro name (e.g., "toc", "excerpt", "info")
|
|
516
|
+
parameters: Macro parameters as key-value pairs
|
|
517
|
+
extension_type: Confluence extension type (default: com.atlassian.confluence.macro.core)
|
|
518
|
+
"""
|
|
519
|
+
|
|
520
|
+
extension_key: str = ""
|
|
521
|
+
parameters: Dict[str, str] = field(default_factory=dict)
|
|
522
|
+
extension_type: str = "com.atlassian.confluence.macro.core"
|
|
523
|
+
|
|
524
|
+
def __post_init__(self) -> None:
|
|
525
|
+
"""Initialize type."""
|
|
526
|
+
self.type = "extension"
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
@dataclass
|
|
530
|
+
class TocNode(ExtensionNode):
|
|
531
|
+
"""
|
|
532
|
+
Node for Table of Contents macro.
|
|
533
|
+
|
|
534
|
+
Generates an automatic table of contents from page headings.
|
|
535
|
+
|
|
536
|
+
Attributes:
|
|
537
|
+
max_level: Maximum heading level to include (1-7, default: 7)
|
|
538
|
+
min_level: Minimum heading level to include (1-7, default: 1)
|
|
539
|
+
include: Regex pattern for headings to include
|
|
540
|
+
exclude: Regex pattern for headings to exclude
|
|
541
|
+
toc_type: Display style - "list" or "flat"
|
|
542
|
+
printable: Include printable version
|
|
543
|
+
separator: Separator for flat type
|
|
544
|
+
"""
|
|
545
|
+
|
|
546
|
+
max_level: int = 7
|
|
547
|
+
min_level: int = 1
|
|
548
|
+
include: Optional[str] = None
|
|
549
|
+
exclude: Optional[str] = None
|
|
550
|
+
toc_type: str = "list" # list or flat
|
|
551
|
+
printable: bool = True
|
|
552
|
+
separator: str = "dots"
|
|
553
|
+
|
|
554
|
+
def __post_init__(self) -> None:
|
|
555
|
+
"""Initialize type and extension_key."""
|
|
556
|
+
self.type = "toc"
|
|
557
|
+
self.extension_key = "toc"
|
|
558
|
+
|
|
559
|
+
# Build parameters dict from attributes
|
|
560
|
+
self.parameters = {}
|
|
561
|
+
if self.max_level != 7:
|
|
562
|
+
self.parameters["maxLevel"] = str(self.max_level)
|
|
563
|
+
if self.min_level != 1:
|
|
564
|
+
self.parameters["minLevel"] = str(self.min_level)
|
|
565
|
+
if self.include:
|
|
566
|
+
self.parameters["include"] = self.include
|
|
567
|
+
if self.exclude:
|
|
568
|
+
self.parameters["exclude"] = self.exclude
|
|
569
|
+
if self.toc_type != "list":
|
|
570
|
+
self.parameters["type"] = self.toc_type
|
|
571
|
+
if not self.printable:
|
|
572
|
+
self.parameters["printable"] = "false"
|
|
573
|
+
if self.separator != "dots":
|
|
574
|
+
self.parameters["separator"] = self.separator
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
@dataclass
|
|
578
|
+
class ExcerptNode(ExtensionNode):
|
|
579
|
+
"""
|
|
580
|
+
Node for Excerpt macro.
|
|
581
|
+
|
|
582
|
+
Defines a page excerpt that appears in search results and page listings.
|
|
583
|
+
The excerpt content is stored in the children list.
|
|
584
|
+
|
|
585
|
+
Attributes:
|
|
586
|
+
hidden: Hide excerpt from page content (only show in listings)
|
|
587
|
+
atlassian_macro_output_type: Output type (BLOCK or INLINE)
|
|
588
|
+
"""
|
|
589
|
+
|
|
590
|
+
hidden: bool = False
|
|
591
|
+
atlassian_macro_output_type: str = "BLOCK"
|
|
592
|
+
|
|
593
|
+
def __post_init__(self) -> None:
|
|
594
|
+
"""Initialize type and extension_key."""
|
|
595
|
+
self.type = "excerpt"
|
|
596
|
+
self.extension_key = "excerpt"
|
|
597
|
+
|
|
598
|
+
# Build parameters dict from attributes
|
|
599
|
+
self.parameters = {}
|
|
600
|
+
if self.hidden:
|
|
601
|
+
self.parameters["hidden"] = "true"
|
|
602
|
+
if self.atlassian_macro_output_type != "BLOCK":
|
|
603
|
+
self.parameters["atlassian-macro-output-type"] = self.atlassian_macro_output_type
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
@dataclass
|
|
607
|
+
class InfoNode(ExtensionNode):
|
|
608
|
+
"""
|
|
609
|
+
Node for Info panel macro.
|
|
610
|
+
|
|
611
|
+
Creates a colored information panel for highlighting important content.
|
|
612
|
+
Content is stored in the children list.
|
|
613
|
+
|
|
614
|
+
Attributes:
|
|
615
|
+
title: Panel title (optional)
|
|
616
|
+
icon: Whether to show icon (default: true)
|
|
617
|
+
"""
|
|
618
|
+
|
|
619
|
+
title: Optional[str] = None
|
|
620
|
+
icon: bool = True
|
|
621
|
+
|
|
622
|
+
def __post_init__(self) -> None:
|
|
623
|
+
"""Initialize type and extension_key."""
|
|
624
|
+
self.type = "info"
|
|
625
|
+
self.extension_key = "info"
|
|
626
|
+
|
|
627
|
+
# Build parameters dict from attributes
|
|
628
|
+
self.parameters = {}
|
|
629
|
+
if self.title:
|
|
630
|
+
self.parameters["title"] = self.title
|
|
631
|
+
if not self.icon:
|
|
632
|
+
self.parameters["icon"] = "false"
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
@dataclass
|
|
636
|
+
class WarningNode(ExtensionNode):
|
|
637
|
+
"""
|
|
638
|
+
Node for Warning panel macro.
|
|
639
|
+
|
|
640
|
+
Creates a colored warning panel for highlighting cautions.
|
|
641
|
+
Content is stored in the children list.
|
|
642
|
+
|
|
643
|
+
Attributes:
|
|
644
|
+
title: Panel title (optional)
|
|
645
|
+
icon: Whether to show icon (default: true)
|
|
646
|
+
"""
|
|
647
|
+
|
|
648
|
+
title: Optional[str] = None
|
|
649
|
+
icon: bool = True
|
|
650
|
+
|
|
651
|
+
def __post_init__(self) -> None:
|
|
652
|
+
"""Initialize type and extension_key."""
|
|
653
|
+
self.type = "warning"
|
|
654
|
+
self.extension_key = "warning"
|
|
655
|
+
|
|
656
|
+
# Build parameters dict from attributes
|
|
657
|
+
self.parameters = {}
|
|
658
|
+
if self.title:
|
|
659
|
+
self.parameters["title"] = self.title
|
|
660
|
+
if not self.icon:
|
|
661
|
+
self.parameters["icon"] = "false"
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
@dataclass
|
|
665
|
+
class NoteNode(ExtensionNode):
|
|
666
|
+
"""
|
|
667
|
+
Node for Note panel macro.
|
|
668
|
+
|
|
669
|
+
Creates a colored note panel for additional information.
|
|
670
|
+
Content is stored in the children list.
|
|
671
|
+
|
|
672
|
+
Attributes:
|
|
673
|
+
title: Panel title (optional)
|
|
674
|
+
icon: Whether to show icon (default: true)
|
|
675
|
+
"""
|
|
676
|
+
|
|
677
|
+
title: Optional[str] = None
|
|
678
|
+
icon: bool = True
|
|
679
|
+
|
|
680
|
+
def __post_init__(self) -> None:
|
|
681
|
+
"""Initialize type and extension_key."""
|
|
682
|
+
self.type = "note"
|
|
683
|
+
self.extension_key = "note"
|
|
684
|
+
|
|
685
|
+
# Build parameters dict from attributes
|
|
686
|
+
self.parameters = {}
|
|
687
|
+
if self.title:
|
|
688
|
+
self.parameters["title"] = self.title
|
|
689
|
+
if not self.icon:
|
|
690
|
+
self.parameters["icon"] = "false"
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
@dataclass
|
|
694
|
+
class PanelNode(ExtensionNode):
|
|
695
|
+
"""
|
|
696
|
+
Node for generic Panel macro.
|
|
697
|
+
|
|
698
|
+
Creates a generic panel (can also be used for tip, success, error panels).
|
|
699
|
+
Content is stored in the children list.
|
|
700
|
+
|
|
701
|
+
Attributes:
|
|
702
|
+
panel_type: Type of panel (info, warning, note, tip, success, error)
|
|
703
|
+
title: Panel title (optional)
|
|
704
|
+
icon: Whether to show icon (default: true)
|
|
705
|
+
"""
|
|
706
|
+
|
|
707
|
+
panel_type: str = "info"
|
|
708
|
+
title: Optional[str] = None
|
|
709
|
+
icon: bool = True
|
|
710
|
+
|
|
711
|
+
def __post_init__(self) -> None:
|
|
712
|
+
"""Initialize type and extension_key."""
|
|
713
|
+
self.type = "panel"
|
|
714
|
+
self.extension_key = self.panel_type # Use panel_type as extension_key
|
|
715
|
+
|
|
716
|
+
# Build parameters dict from attributes
|
|
717
|
+
self.parameters = {}
|
|
718
|
+
if self.title:
|
|
719
|
+
self.parameters["title"] = self.title
|
|
720
|
+
if not self.icon:
|
|
721
|
+
self.parameters["icon"] = "false"
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
@dataclass
|
|
725
|
+
class ExpandMacroNode(ExtensionNode):
|
|
726
|
+
"""
|
|
727
|
+
Node for Expand macro (collapsible section).
|
|
728
|
+
|
|
729
|
+
Creates a collapsible content section with a title.
|
|
730
|
+
Content is stored in the children list.
|
|
731
|
+
|
|
732
|
+
Attributes:
|
|
733
|
+
title: Title shown in the expand header
|
|
734
|
+
"""
|
|
735
|
+
|
|
736
|
+
title: str = ""
|
|
737
|
+
|
|
738
|
+
def __post_init__(self) -> None:
|
|
739
|
+
"""Initialize type and extension_key."""
|
|
740
|
+
self.type = "expandMacro"
|
|
741
|
+
self.extension_key = "expand"
|
|
742
|
+
|
|
743
|
+
# Build parameters dict from attributes
|
|
744
|
+
self.parameters = {}
|
|
745
|
+
if self.title:
|
|
746
|
+
self.parameters["title"] = self.title
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
@dataclass
|
|
750
|
+
class StatusMacroNode(ExtensionNode):
|
|
751
|
+
"""
|
|
752
|
+
Node for Status lozenge macro.
|
|
753
|
+
|
|
754
|
+
Creates an inline status badge with color and text.
|
|
755
|
+
|
|
756
|
+
Attributes:
|
|
757
|
+
status_text: Status text to display
|
|
758
|
+
color: Status color (Green, Yellow, Red, Blue, Grey)
|
|
759
|
+
subtle: Use subtle style (default: false)
|
|
760
|
+
"""
|
|
761
|
+
|
|
762
|
+
status_text: str = ""
|
|
763
|
+
color: str = "Grey"
|
|
764
|
+
subtle: bool = False
|
|
765
|
+
|
|
766
|
+
def __post_init__(self) -> None:
|
|
767
|
+
"""Initialize type and extension_key."""
|
|
768
|
+
self.type = "statusMacro"
|
|
769
|
+
self.extension_key = "status"
|
|
770
|
+
|
|
771
|
+
# Build parameters dict from attributes
|
|
772
|
+
self.parameters = {}
|
|
773
|
+
if self.status_text:
|
|
774
|
+
self.parameters["title"] = self.status_text
|
|
775
|
+
if self.color:
|
|
776
|
+
self.parameters["colour"] = self.color # Confluence uses British spelling
|
|
777
|
+
if self.subtle:
|
|
778
|
+
self.parameters["subtle"] = "true"
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
@dataclass
|
|
782
|
+
class CodeBlockMacroNode(ExtensionNode):
|
|
783
|
+
"""
|
|
784
|
+
Node for enhanced Code Block macro.
|
|
785
|
+
|
|
786
|
+
Creates a code block with enhanced features like title and line numbers.
|
|
787
|
+
Code content is stored in the children list or content attribute.
|
|
788
|
+
|
|
789
|
+
Attributes:
|
|
790
|
+
language: Programming language for syntax highlighting
|
|
791
|
+
title: Code block title
|
|
792
|
+
linenumbers: Show line numbers (default: false)
|
|
793
|
+
theme: Syntax highlighting theme
|
|
794
|
+
collapse: Collapsible code block (default: false)
|
|
795
|
+
"""
|
|
796
|
+
|
|
797
|
+
language: Optional[str] = None
|
|
798
|
+
title: Optional[str] = None
|
|
799
|
+
linenumbers: bool = False
|
|
800
|
+
theme: Optional[str] = None
|
|
801
|
+
collapse: bool = False
|
|
802
|
+
|
|
803
|
+
def __post_init__(self) -> None:
|
|
804
|
+
"""Initialize type and extension_key."""
|
|
805
|
+
self.type = "codeBlockMacro"
|
|
806
|
+
self.extension_key = "code"
|
|
807
|
+
|
|
808
|
+
# Build parameters dict from attributes
|
|
809
|
+
self.parameters = {}
|
|
810
|
+
if self.language:
|
|
811
|
+
self.parameters["language"] = self.language
|
|
812
|
+
if self.title:
|
|
813
|
+
self.parameters["title"] = self.title
|
|
814
|
+
if self.linenumbers:
|
|
815
|
+
self.parameters["linenumbers"] = "true"
|
|
816
|
+
if self.theme:
|
|
817
|
+
self.parameters["theme"] = self.theme
|
|
818
|
+
if self.collapse:
|
|
819
|
+
self.parameters["collapse"] = "true"
|