roborean-documents-markdown 0.1.2__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.
@@ -0,0 +1,156 @@
1
+ """Markdown / CommonMark document driver."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import UTC, datetime
5
+ from typing import Any, Mapping
6
+
7
+ from roborean_documents_base.capabilities import assert_op_allowed
8
+ from roborean_spec import (
9
+ DocumentDriverManifest,
10
+ DocumentOperation,
11
+ DocumentPreview,
12
+ TemplateManifest,
13
+ )
14
+
15
+
16
+ @dataclass
17
+ class MarkdownSession:
18
+ """AST buffer for Markdown generation."""
19
+
20
+ document_id: str
21
+ driver_id: str
22
+ nodes: list[dict[str, Any]] = field(default_factory=list)
23
+ ops_applied: list[dict[str, Any]] = field(default_factory=list)
24
+ template_prefix: str = ""
25
+
26
+
27
+ def render_commonmark(nodes: list[dict[str, Any]], prefix: str = "") -> str:
28
+ """Render a minimal node list to CommonMark."""
29
+ parts: list[str] = []
30
+ if prefix:
31
+ parts.append(prefix.rstrip("\n"))
32
+ for node in nodes:
33
+ kind = node["kind"]
34
+ if kind == "heading":
35
+ parts.append("#" * int(node["level"]) + " " + node["text"])
36
+ elif kind == "paragraph":
37
+ parts.append(node["text"])
38
+ elif kind == "table":
39
+ rows = node["rows"]
40
+ if not rows:
41
+ continue
42
+ header = rows[0]
43
+ parts.append("| " + " | ".join(header) + " |")
44
+ parts.append("| " + " | ".join("---" for _ in header) + " |")
45
+ for row in rows[1:]:
46
+ parts.append("| " + " | ".join(row) + " |")
47
+ body = "\n\n".join(parts).rstrip() + "\n"
48
+ return body
49
+
50
+
51
+ class MarkdownDocumentDriver:
52
+ """CommonMark driver using flow operations."""
53
+
54
+ driver_id = "roborean.markdown"
55
+ manifest = DocumentDriverManifest(
56
+ driverId="roborean.markdown",
57
+ version="0.3.0",
58
+ irFamily="flow",
59
+ capabilities=[
60
+ "set_metadata",
61
+ "replace_named_value",
62
+ "flow.insert_paragraph",
63
+ "flow.insert_heading",
64
+ "flow.replace_table_rows",
65
+ "plain.append_text",
66
+ "finalize",
67
+ ],
68
+ supportsPreview=True,
69
+ supportsBrowserExecution=True,
70
+ supportsDiff=True,
71
+ requiresBackend=False,
72
+ templateMediaTypes=["text/markdown"],
73
+ )
74
+
75
+ def __init__(self) -> None:
76
+ """Initialize empty template state."""
77
+ self._template = ""
78
+ self._manifest: TemplateManifest | None = None
79
+
80
+ def load_template(self, template_ref, *, store, manifest) -> None:
81
+ """Load Markdown template prefix."""
82
+ text = store.load_bytes(template_ref).decode("utf-8")
83
+ self._template = text.replace("\r\n", "\n")
84
+ self._manifest = manifest
85
+
86
+ def begin_session(
87
+ self, workspace, metadata: Mapping[str, Any]
88
+ ) -> MarkdownSession:
89
+ """Start a Markdown session."""
90
+ return MarkdownSession(
91
+ document_id=str(metadata.get("documentId", "")),
92
+ driver_id=self.driver_id,
93
+ template_prefix=self._template,
94
+ )
95
+
96
+ def apply_operation(
97
+ self, session: MarkdownSession, op: DocumentOperation
98
+ ) -> None:
99
+ """Apply one flow/plain operation."""
100
+ assert_op_allowed(self.manifest, op)
101
+ data = op.model_dump(mode="python", by_alias=True)
102
+ session.ops_applied.append(op.model_dump(mode="json", by_alias=True))
103
+ if op.op == "flow.insert_heading":
104
+ session.nodes.append(
105
+ {
106
+ "kind": "heading",
107
+ "level": data["level"],
108
+ "text": data["text"],
109
+ }
110
+ )
111
+ elif op.op == "flow.insert_paragraph":
112
+ text = "".join(run["text"] for run in data["runs"])
113
+ session.nodes.append({"kind": "paragraph", "text": text})
114
+ elif op.op == "flow.replace_table_rows":
115
+ session.nodes.append(
116
+ {"kind": "table", "table": data["table"], "rows": data["rows"]}
117
+ )
118
+ elif op.op == "plain.append_text":
119
+ session.nodes.append({"kind": "paragraph", "text": data["text"]})
120
+ elif op.op == "replace_named_value":
121
+ value = data["value"]
122
+ if isinstance(value, dict) and "value" in value:
123
+ rendered = str(value["value"])
124
+ else:
125
+ rendered = str(value)
126
+ session.template_prefix = session.template_prefix.replace(
127
+ "{{" + str(data["name"]) + "}}", rendered
128
+ )
129
+
130
+ def finalize(self, session: MarkdownSession) -> None:
131
+ """No-op finalize."""
132
+ return
133
+
134
+ def serialize(self, session: MarkdownSession) -> bytes:
135
+ """Return CommonMark UTF-8 bytes."""
136
+ body = render_commonmark(session.nodes, session.template_prefix)
137
+ return body.encode("utf-8")
138
+
139
+ def preview(self, session: MarkdownSession) -> DocumentPreview:
140
+ """Identity preview of CommonMark text."""
141
+ return DocumentPreview(
142
+ documentId=session.document_id,
143
+ mode="text",
144
+ body=self.serialize(session).decode("utf-8"),
145
+ warnings=[],
146
+ generatedAt=datetime.now(UTC).isoformat(),
147
+ renderer={
148
+ "package": "roborean-documents-markdown",
149
+ "version": "0.3.0",
150
+ },
151
+ )
152
+
153
+
154
+ def create_driver() -> MarkdownDocumentDriver:
155
+ """Entry-point factory."""
156
+ return MarkdownDocumentDriver()
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: roborean-documents-markdown
3
+ Version: 0.1.2
4
+ Summary: Markdown document driver for Roborean
5
+ Project-URL: Homepage, https://github.com/TNick/roborean
6
+ Project-URL: Repository, https://github.com/TNick/roborean
7
+ License-Expression: MIT
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: roborean-documents-base>=0.1.1
10
+ Requires-Dist: roborean-spec>=0.1.1
@@ -0,0 +1,5 @@
1
+ roborean_documents_markdown/driver.py,sha256=BP_N0NjFOaQteKyxhGL5RjW1snBzN9rq03VjJUzDrho,5329
2
+ roborean_documents_markdown-0.1.2.dist-info/METADATA,sha256=JWUPNBHkpQRNspYGXC7KljYXIrbHKzJb1oV5O-d_1SI,364
3
+ roborean_documents_markdown-0.1.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
4
+ roborean_documents_markdown-0.1.2.dist-info/entry_points.txt,sha256=KXbgcop3F9XoaPCZxratAMcIMYcJAmhqRRAfB9Qu510,97
5
+ roborean_documents_markdown-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [roborean.document_drivers]
2
+ roborean.markdown = roborean_documents_markdown.driver:create_driver