roborean-documents-text 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,122 @@
|
|
|
1
|
+
"""Plain-text document driver."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from datetime import UTC, datetime
|
|
5
|
+
from typing import Any, Mapping
|
|
6
|
+
|
|
7
|
+
from pydantic import TypeAdapter
|
|
8
|
+
from roborean_documents_base.capabilities import assert_op_allowed
|
|
9
|
+
from roborean_documents_base.resolve_values import public_literal_value
|
|
10
|
+
from roborean_spec import (
|
|
11
|
+
DocumentDriverManifest,
|
|
12
|
+
DocumentOperation,
|
|
13
|
+
DocumentPreview,
|
|
14
|
+
TemplateManifest,
|
|
15
|
+
WorkspaceValue,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class TextSession:
|
|
21
|
+
"""In-memory text generation session."""
|
|
22
|
+
|
|
23
|
+
document_id: str
|
|
24
|
+
driver_id: str
|
|
25
|
+
body: str
|
|
26
|
+
ops_applied: list[dict[str, Any]] = field(default_factory=list)
|
|
27
|
+
finalized: bool = False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TextDocumentDriver:
|
|
31
|
+
"""UTF-8 text driver using Mustache-like ``{{slot}}`` replacement."""
|
|
32
|
+
|
|
33
|
+
driver_id = "roborean.text"
|
|
34
|
+
manifest = DocumentDriverManifest(
|
|
35
|
+
driverId="roborean.text",
|
|
36
|
+
version="0.3.0",
|
|
37
|
+
irFamily="plain",
|
|
38
|
+
capabilities=[
|
|
39
|
+
"set_metadata",
|
|
40
|
+
"replace_named_value",
|
|
41
|
+
"plain.append_text",
|
|
42
|
+
"plain.replace_all",
|
|
43
|
+
"finalize",
|
|
44
|
+
],
|
|
45
|
+
supportsPreview=True,
|
|
46
|
+
supportsBrowserExecution=True,
|
|
47
|
+
supportsDiff=True,
|
|
48
|
+
requiresBackend=False,
|
|
49
|
+
templateMediaTypes=["text/plain"],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def __init__(self) -> None:
|
|
53
|
+
"""Initialize empty template state."""
|
|
54
|
+
self._template = ""
|
|
55
|
+
self._manifest: TemplateManifest | None = None
|
|
56
|
+
|
|
57
|
+
def load_template(self, template_ref, *, store, manifest) -> None:
|
|
58
|
+
"""Load UTF-8 template bytes."""
|
|
59
|
+
# Normalize newlines so Windows-checked-out templates stay portable.
|
|
60
|
+
text = store.load_bytes(template_ref).decode("utf-8")
|
|
61
|
+
self._template = text.replace("\r\n", "\n")
|
|
62
|
+
self._manifest = manifest
|
|
63
|
+
|
|
64
|
+
def begin_session(
|
|
65
|
+
self, workspace, metadata: Mapping[str, Any]
|
|
66
|
+
) -> TextSession:
|
|
67
|
+
"""Start a session from the loaded template."""
|
|
68
|
+
return TextSession(
|
|
69
|
+
document_id=str(metadata.get("documentId", "")),
|
|
70
|
+
driver_id=self.driver_id,
|
|
71
|
+
body=self._template,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def apply_operation(
|
|
75
|
+
self, session: TextSession, op: DocumentOperation
|
|
76
|
+
) -> None:
|
|
77
|
+
"""Apply one plain-text operation."""
|
|
78
|
+
assert_op_allowed(self.manifest, op)
|
|
79
|
+
data = op.model_dump(mode="python", by_alias=True)
|
|
80
|
+
session.ops_applied.append(op.model_dump(mode="json", by_alias=True))
|
|
81
|
+
if op.op == "replace_named_value":
|
|
82
|
+
value = TypeAdapter(WorkspaceValue).validate_python(data["value"])
|
|
83
|
+
session.body = session.body.replace(
|
|
84
|
+
"{{" + str(data["name"]) + "}}",
|
|
85
|
+
str(public_literal_value(value)),
|
|
86
|
+
)
|
|
87
|
+
elif op.op == "plain.append_text":
|
|
88
|
+
session.body += str(data["text"])
|
|
89
|
+
elif op.op == "plain.replace_all":
|
|
90
|
+
session.body = session.body.replace(
|
|
91
|
+
str(data["find"]), str(data["replace"])
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def finalize(self, session: TextSession) -> None:
|
|
95
|
+
"""Mark the session finalized."""
|
|
96
|
+
session.finalized = True
|
|
97
|
+
|
|
98
|
+
def serialize(self, session: TextSession) -> bytes:
|
|
99
|
+
"""Return UTF-8 bytes with a trailing newline."""
|
|
100
|
+
body = session.body
|
|
101
|
+
if not body.endswith("\n"):
|
|
102
|
+
body += "\n"
|
|
103
|
+
return body.encode("utf-8")
|
|
104
|
+
|
|
105
|
+
def preview(self, session: TextSession) -> DocumentPreview:
|
|
106
|
+
"""Return a text preview identical to serialization."""
|
|
107
|
+
return DocumentPreview(
|
|
108
|
+
documentId=session.document_id,
|
|
109
|
+
mode="text",
|
|
110
|
+
body=self.serialize(session).decode("utf-8"),
|
|
111
|
+
warnings=[],
|
|
112
|
+
generatedAt=datetime.now(UTC).isoformat(),
|
|
113
|
+
renderer={
|
|
114
|
+
"package": "roborean-documents-text",
|
|
115
|
+
"version": "0.3.0",
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def create_driver() -> TextDocumentDriver:
|
|
121
|
+
"""Entry-point factory."""
|
|
122
|
+
return TextDocumentDriver()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: roborean-documents-text
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Plain-text 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_text/driver.py,sha256=mCMGOobz4U2O-iAds1xgmmXjMT3-3tzotwtUWJL9sxk,3982
|
|
2
|
+
roborean_documents_text-0.1.2.dist-info/METADATA,sha256=u4yFoWpMBhIsrr38mP-yIOyMq1X1aPqFi6rK-2Jh6qA,362
|
|
3
|
+
roborean_documents_text-0.1.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
4
|
+
roborean_documents_text-0.1.2.dist-info/entry_points.txt,sha256=KD_86SSg75MHmg55D_VtRuD925_wEAo2KCDer1GcnFg,89
|
|
5
|
+
roborean_documents_text-0.1.2.dist-info/RECORD,,
|