python-fragments 0.10__tar.gz → 0.14__tar.gz
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.
- {python_fragments-0.10 → python_fragments-0.14}/PKG-INFO +1 -1
- {python_fragments-0.10 → python_fragments-0.14}/fragments/ast_nodes.py +199 -79
- python_fragments-0.14/fragments/cli.py +44 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/grammar.py +94 -33
- {python_fragments-0.10 → python_fragments-0.14}/fragments/html/elements.py +1 -1
- {python_fragments-0.10 → python_fragments-0.14}/fragments/source.py +7 -0
- {python_fragments-0.10 → python_fragments-0.14}/pyproject.toml +1 -1
- {python_fragments-0.10 → python_fragments-0.14}/python_fragments.egg-info/PKG-INFO +1 -1
- python_fragments-0.14/tests/test_grammar.py +333 -0
- {python_fragments-0.10 → python_fragments-0.14}/tests/test_source_map.py +113 -2
- python_fragments-0.10/fragments/cli.py +0 -20
- python_fragments-0.10/tests/test_grammar.py +0 -86
- {python_fragments-0.10 → python_fragments-0.14}/README.md +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/__init__.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/html/__init__.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/loader.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/__init__.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/based_proxy.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/__init__.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/code_actions.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/completion.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/definition.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/diagnostics.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/document_highlight.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/document_symbols.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/folding_range.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/hover.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/inlay_hints.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/lifecycle.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/references.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/rename.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/semantic_tokens.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/client_message_handlers/signature_help.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/file_state.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/message_queue.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/pyright_notification_handlers/__init__.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/pyright_notification_handlers/capability.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/pyright_notification_handlers/configuration.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/pyright_notification_handlers/diagnostics.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/lsp/types.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/fragments/transpiler.py +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/python_fragments.egg-info/SOURCES.txt +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/python_fragments.egg-info/dependency_links.txt +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/python_fragments.egg-info/entry_points.txt +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/python_fragments.egg-info/requires.txt +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/python_fragments.egg-info/top_level.txt +0 -0
- {python_fragments-0.10 → python_fragments-0.14}/setup.cfg +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
from typing import Sequence
|
|
3
3
|
|
|
4
|
+
type ASTHTMLChild = ASTHTMLElement | ASTHTMLComment | ASTHTMLText | ASTInterpolation | ASTComponent | ASTControlNode
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
@dataclass(slots=True)
|
|
6
8
|
class ASTModule:
|
|
@@ -29,12 +31,12 @@ class ASTModule:
|
|
|
29
31
|
|
|
30
32
|
def map_offset(self, offset: int) -> int | None:
|
|
31
33
|
for owner in self.children:
|
|
32
|
-
if owner.source_start
|
|
34
|
+
if owner.source_start <= offset <= owner.source_end:
|
|
33
35
|
return owner.map_offset(offset)
|
|
34
36
|
|
|
35
37
|
def unmap_offset(self, offset: int) -> int | None:
|
|
36
38
|
for owner in self.children:
|
|
37
|
-
if owner.transpiled_start
|
|
39
|
+
if owner.transpiled_start <= offset <= owner.transpiled_end:
|
|
38
40
|
return owner.unmap_offset(offset)
|
|
39
41
|
|
|
40
42
|
|
|
@@ -56,14 +58,14 @@ class ASTPython:
|
|
|
56
58
|
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
57
59
|
|
|
58
60
|
def map_offset(self, offset: int) -> int | None:
|
|
59
|
-
if self.source_start
|
|
61
|
+
if self.source_start <= offset <= self.source_end:
|
|
60
62
|
specific_offset = offset - self.source_start
|
|
61
63
|
return self.transpiled_start + specific_offset
|
|
62
64
|
|
|
63
65
|
return None
|
|
64
66
|
|
|
65
67
|
def unmap_offset(self, offset: int) -> int | None:
|
|
66
|
-
if self.transpiled_start
|
|
68
|
+
if self.transpiled_start <= offset <= self.transpiled_end:
|
|
67
69
|
specific_offset = offset - self.transpiled_start
|
|
68
70
|
return self.source_start + specific_offset
|
|
69
71
|
|
|
@@ -75,7 +77,7 @@ class ASTFragment:
|
|
|
75
77
|
source_start: int = field(compare=False)
|
|
76
78
|
source_end: int = field(compare=False)
|
|
77
79
|
|
|
78
|
-
children: list["
|
|
80
|
+
children: list["ASTHTMLChild"]
|
|
79
81
|
|
|
80
82
|
transpiled_content: str = field(init=False)
|
|
81
83
|
transpiled_start: int = field(init=False)
|
|
@@ -96,14 +98,14 @@ class ASTFragment:
|
|
|
96
98
|
|
|
97
99
|
def map_offset(self, offset: int) -> int | None:
|
|
98
100
|
for owner in self.children:
|
|
99
|
-
if owner.source_start
|
|
101
|
+
if owner.source_start <= offset <= owner.source_end:
|
|
100
102
|
return owner.map_offset(offset)
|
|
101
103
|
|
|
102
104
|
return None
|
|
103
105
|
|
|
104
106
|
def unmap_offset(self, offset: int) -> int | None:
|
|
105
107
|
for owner in self.children:
|
|
106
|
-
if owner.transpiled_start
|
|
108
|
+
if owner.transpiled_start <= offset <= owner.transpiled_end:
|
|
107
109
|
return owner.unmap_offset(offset)
|
|
108
110
|
|
|
109
111
|
return None
|
|
@@ -116,114 +118,229 @@ class ASTHTMLElement:
|
|
|
116
118
|
|
|
117
119
|
name: str
|
|
118
120
|
attributes: dict[str, "ASTHTMLAttribute"]
|
|
119
|
-
|
|
120
|
-
for_attribute: "ASTInterpolation | None"
|
|
121
|
-
children: Sequence["ASTHTMLElement | ASTHTMLComment | ASTHTMLText | ASTInterpolation"]
|
|
121
|
+
children: Sequence["ASTHTMLChild"]
|
|
122
122
|
one_line: bool
|
|
123
123
|
|
|
124
124
|
transpiled_content: str = field(init=False)
|
|
125
125
|
transpiled_start: int = field(init=False)
|
|
126
126
|
transpiled_end: int = field(init=False)
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
__if_template__: str = """{} if {} else ''"""
|
|
130
|
-
__element_template__: str = """el("{}",[{}],oneline={},{})"""
|
|
131
|
-
__component_template__: str = """{}([{}],{})"""
|
|
128
|
+
__element_template__: str = """el("{}",[{}],oneline={},attributes={})"""
|
|
132
129
|
|
|
133
130
|
def transpile(self, transpiled_start: int) -> None:
|
|
134
131
|
self.transpiled_start = transpiled_start
|
|
135
|
-
|
|
136
|
-
if self.for_attribute is not None:
|
|
137
|
-
transpiled_start += 10
|
|
138
|
-
|
|
139
|
-
if self.name[0].capitalize() == self.name[0]:
|
|
140
|
-
self._transpile_component_call(transpiled_start)
|
|
141
|
-
else:
|
|
142
|
-
self._transpile_element_call(transpiled_start)
|
|
143
|
-
|
|
144
|
-
if self.if_attribute is not None:
|
|
145
|
-
self.if_attribute.transpile(self.transpiled_end + 4)
|
|
146
|
-
self.transpiled_content = self.__if_template__.format(self.transpiled_content, self.if_attribute.transpiled_content)
|
|
147
|
-
self.transpiled_end = self.if_attribute.transpiled_end + 8
|
|
148
|
-
elif self.for_attribute is not None:
|
|
149
|
-
self.for_attribute.transpile(self.transpiled_end + 5)
|
|
150
|
-
self.transpiled_content = self.__for_template__.format(self.transpiled_content, self.for_attribute.transpiled_content)
|
|
151
|
-
self.transpiled_end = self.for_attribute.transpiled_end + 2
|
|
152
|
-
|
|
153
|
-
def _transpile_element_call(self, start: int) -> None:
|
|
154
|
-
transpiled_start = start + len(self.name) + 7
|
|
132
|
+
transpiled_start = transpiled_start + len(self.name) + 7
|
|
155
133
|
for child in self.children:
|
|
156
134
|
child.transpile(transpiled_start)
|
|
157
135
|
transpiled_start = child.transpiled_end + 1
|
|
158
|
-
|
|
136
|
+
if self.children:
|
|
137
|
+
transpiled_start -= 1
|
|
159
138
|
children = ",".join(child.transpiled_content for child in self.children)
|
|
160
|
-
|
|
161
139
|
oneline_offset = len(str(self.one_line))
|
|
162
|
-
|
|
163
|
-
transpiled_start += 10 + oneline_offset + 1
|
|
164
|
-
|
|
140
|
+
transpiled_start += 10 + oneline_offset + 12 + 1 # ],oneline= + oneline + ,attributes= + {
|
|
165
141
|
for attribute in self.attributes.values():
|
|
166
142
|
attribute.transpile(transpiled_start)
|
|
167
143
|
transpiled_start = attribute.transpiled_end + 1
|
|
168
144
|
transpiled_start -= 1
|
|
169
145
|
|
|
170
|
-
attributes = ",".join(attribute.transpiled_content for attribute in self.attributes.values())
|
|
146
|
+
attributes = "{" + ",".join(attribute.transpiled_content for attribute in self.attributes.values()) + "}"
|
|
171
147
|
self.transpiled_content = self.__element_template__.format(self.name, children, self.one_line, attributes)
|
|
172
|
-
self.transpiled_end =
|
|
148
|
+
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
149
|
+
|
|
150
|
+
def map_offset(self, offset: int) -> int | None:
|
|
151
|
+
for attribute in self.attributes.values():
|
|
152
|
+
if attribute.source_start <= offset <= attribute.source_end:
|
|
153
|
+
return attribute.map_offset(offset)
|
|
154
|
+
|
|
155
|
+
for child in self.children:
|
|
156
|
+
if child.source_start <= offset <= child.source_end:
|
|
157
|
+
return child.map_offset(offset)
|
|
158
|
+
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
def unmap_offset(self, offset: int) -> int | None:
|
|
162
|
+
for attribute in self.attributes.values():
|
|
163
|
+
if attribute.transpiled_start <= offset <= attribute.transpiled_end:
|
|
164
|
+
return attribute.unmap_offset(offset)
|
|
173
165
|
|
|
174
|
-
|
|
175
|
-
|
|
166
|
+
for child in self.children:
|
|
167
|
+
if child.transpiled_start <= offset <= child.transpiled_end:
|
|
168
|
+
return child.unmap_offset(offset)
|
|
169
|
+
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@dataclass(slots=True)
|
|
174
|
+
class ASTControlNode[T: (ASTHTMLElement, ASTComponent)]:
|
|
175
|
+
source_start: int = field(compare=False)
|
|
176
|
+
source_end: int = field(compare=False)
|
|
177
|
+
|
|
178
|
+
if_interpolation: "ASTInterpolation | None"
|
|
179
|
+
for_interpolation: "ASTInterpolation | None"
|
|
180
|
+
child: T
|
|
181
|
+
|
|
182
|
+
transpiled_content: str = field(init=False)
|
|
183
|
+
transpiled_start: int = field(init=False)
|
|
184
|
+
transpiled_end: int = field(init=False)
|
|
185
|
+
|
|
186
|
+
__for_template__: str = "sequence([{} for {}])"
|
|
187
|
+
__if_template__: str = "{} if {} else ''"
|
|
188
|
+
|
|
189
|
+
def transpile(self, transpiled_start: int) -> None:
|
|
190
|
+
self.transpiled_start = transpiled_start
|
|
191
|
+
if self.for_interpolation is not None:
|
|
192
|
+
self.child.transpile(transpiled_start + 10) # sequence([
|
|
193
|
+
self.for_interpolation.transpile(self.child.transpiled_end + 5) # child + for
|
|
194
|
+
self.transpiled_content = self.__for_template__.format(self.child.transpiled_content, self.for_interpolation.transpiled_content)
|
|
195
|
+
elif self.if_interpolation is not None:
|
|
196
|
+
self.child.transpile(transpiled_start)
|
|
197
|
+
self.if_interpolation.transpile(self.child.transpiled_end + 4) # child + if
|
|
198
|
+
self.transpiled_content = self.__if_template__.format(self.child.transpiled_content, self.if_interpolation.transpiled_content)
|
|
199
|
+
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
200
|
+
|
|
201
|
+
def map_offset(self, offset: int) -> int | None:
|
|
202
|
+
if self.if_interpolation is not None and self.if_interpolation.source_start <= offset <= self.if_interpolation.source_end:
|
|
203
|
+
return self.if_interpolation.map_offset(offset)
|
|
204
|
+
|
|
205
|
+
if self.for_interpolation is not None and self.for_interpolation.source_start <= offset <= self.for_interpolation.source_end:
|
|
206
|
+
return self.for_interpolation.map_offset(offset)
|
|
207
|
+
|
|
208
|
+
if self.child.source_start <= offset <= self.child.source_end:
|
|
209
|
+
return self.child.map_offset(offset)
|
|
210
|
+
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
def unmap_offset(self, offset: int) -> int | None:
|
|
214
|
+
if self.child.transpiled_start <= offset <= self.child.transpiled_end:
|
|
215
|
+
return self.child.unmap_offset(offset)
|
|
216
|
+
|
|
217
|
+
if self.if_interpolation is not None and self.if_interpolation.transpiled_start <= offset <= self.if_interpolation.transpiled_end:
|
|
218
|
+
return self.if_interpolation.unmap_offset(offset)
|
|
219
|
+
|
|
220
|
+
if self.for_interpolation is not None and self.for_interpolation.transpiled_start <= offset <= self.for_interpolation.transpiled_end:
|
|
221
|
+
return self.for_interpolation.unmap_offset(offset)
|
|
222
|
+
|
|
223
|
+
return None
|
|
224
|
+
|
|
225
|
+
@classmethod
|
|
226
|
+
def wrap_child(
|
|
227
|
+
cls,
|
|
228
|
+
child: T,
|
|
229
|
+
if_interpolation: "ASTInterpolation | None",
|
|
230
|
+
for_interpolation: "ASTInterpolation | None",
|
|
231
|
+
) -> "ASTControlNode[T] | T":
|
|
232
|
+
"""If the child needs a control node, wrap it."""
|
|
233
|
+
if if_interpolation is None and for_interpolation is None:
|
|
234
|
+
return child
|
|
235
|
+
|
|
236
|
+
return ASTControlNode(child.source_start, child.source_end, if_interpolation, for_interpolation, child)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@dataclass(slots=True)
|
|
240
|
+
class ASTComponent:
|
|
241
|
+
source_start: int = field(compare=False)
|
|
242
|
+
source_end: int = field(compare=False)
|
|
243
|
+
|
|
244
|
+
name: str
|
|
245
|
+
arguments: dict[str, "ASTComponentArgument"]
|
|
246
|
+
children: Sequence["ASTHTMLChild"]
|
|
247
|
+
|
|
248
|
+
transpiled_content: str = field(init=False)
|
|
249
|
+
transpiled_start: int = field(init=False)
|
|
250
|
+
transpiled_end: int = field(init=False)
|
|
251
|
+
|
|
252
|
+
__template__: str = """{}([{}],{})"""
|
|
253
|
+
|
|
254
|
+
def transpile(self, transpiled_start: int) -> None:
|
|
255
|
+
self.transpiled_start = transpiled_start
|
|
256
|
+
transpiled_start = transpiled_start + len(self.name) + 2
|
|
176
257
|
for child in self.children:
|
|
177
258
|
child.transpile(transpiled_start)
|
|
178
259
|
transpiled_start = child.transpiled_end + 1
|
|
179
|
-
|
|
260
|
+
if self.children:
|
|
261
|
+
transpiled_start -= 1
|
|
180
262
|
children = ",".join(child.transpiled_content for child in self.children)
|
|
181
263
|
|
|
182
|
-
if len(self.
|
|
183
|
-
self.transpiled_content = self.
|
|
184
|
-
self.transpiled_end =
|
|
264
|
+
if len(self.arguments) == 0:
|
|
265
|
+
self.transpiled_content = self.__template__.format(self.name, children, "")
|
|
266
|
+
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
185
267
|
return
|
|
186
268
|
|
|
187
269
|
transpiled_start += 2
|
|
188
|
-
for attribute in self.
|
|
270
|
+
for attribute in self.arguments.values():
|
|
189
271
|
attribute.transpile(transpiled_start)
|
|
190
272
|
transpiled_start = attribute.transpiled_end + 1
|
|
191
273
|
|
|
192
|
-
attributes = ",".join(attribute.transpiled_content for attribute in self.
|
|
193
|
-
self.transpiled_content = self.
|
|
194
|
-
self.transpiled_end =
|
|
274
|
+
attributes = ",".join(attribute.transpiled_content for attribute in self.arguments.values())
|
|
275
|
+
self.transpiled_content = self.__template__.format(self.name, children, attributes)
|
|
276
|
+
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
195
277
|
|
|
196
278
|
def map_offset(self, offset: int) -> int | None:
|
|
197
|
-
for attribute in self.
|
|
198
|
-
if attribute.source_start
|
|
279
|
+
for attribute in self.arguments.values():
|
|
280
|
+
if attribute.source_start <= offset <= attribute.source_end:
|
|
199
281
|
return attribute.map_offset(offset)
|
|
200
282
|
|
|
201
283
|
for child in self.children:
|
|
202
|
-
if child.source_start
|
|
284
|
+
if child.source_start <= offset <= child.source_end:
|
|
203
285
|
return child.map_offset(offset)
|
|
204
286
|
|
|
205
|
-
if self.if_attribute is not None and self.if_attribute.source_start < offset <= self.if_attribute.source_end:
|
|
206
|
-
return self.if_attribute.map_offset(offset)
|
|
207
|
-
|
|
208
|
-
if self.for_attribute is not None and self.for_attribute.source_start < offset <= self.for_attribute.source_end:
|
|
209
|
-
return self.for_attribute.map_offset(offset)
|
|
210
|
-
|
|
211
287
|
return None
|
|
212
288
|
|
|
213
289
|
def unmap_offset(self, offset: int) -> int | None:
|
|
214
|
-
for attribute in self.
|
|
215
|
-
if attribute.transpiled_start
|
|
290
|
+
for attribute in self.arguments.values():
|
|
291
|
+
if attribute.transpiled_start <= offset <= attribute.transpiled_end:
|
|
216
292
|
return attribute.unmap_offset(offset)
|
|
217
293
|
|
|
218
294
|
for child in self.children:
|
|
219
|
-
if child.transpiled_start
|
|
295
|
+
if child.transpiled_start <= offset <= child.transpiled_end:
|
|
220
296
|
return child.unmap_offset(offset)
|
|
221
297
|
|
|
222
|
-
|
|
223
|
-
|
|
298
|
+
return None
|
|
299
|
+
|
|
224
300
|
|
|
225
|
-
|
|
226
|
-
|
|
301
|
+
@dataclass(slots=True)
|
|
302
|
+
class ASTComponentArgument:
|
|
303
|
+
source_start: int = field(compare=False)
|
|
304
|
+
source_end: int = field(compare=False)
|
|
305
|
+
|
|
306
|
+
name: str
|
|
307
|
+
string_literal: str | None
|
|
308
|
+
interpolation: "ASTInterpolation | None"
|
|
309
|
+
|
|
310
|
+
transpiled_content: str = field(init=False)
|
|
311
|
+
transpiled_start: int = field(init=False)
|
|
312
|
+
transpiled_end: int = field(init=False)
|
|
313
|
+
|
|
314
|
+
__template__: str = "{}={}"
|
|
315
|
+
|
|
316
|
+
def transpile(self, transpiled_start: int) -> None:
|
|
317
|
+
self.transpiled_start = transpiled_start
|
|
318
|
+
|
|
319
|
+
if self.string_literal is not None:
|
|
320
|
+
self.transpiled_content = self.__template__.format(self.name, self.string_literal)
|
|
321
|
+
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
322
|
+
return
|
|
323
|
+
|
|
324
|
+
assert self.interpolation is not None
|
|
325
|
+
self.interpolation.transpile(self.transpiled_start + len(self.name) + 1)
|
|
326
|
+
self.transpiled_content = self.__template__.format(self.name, self.interpolation.transpiled_content)
|
|
327
|
+
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
328
|
+
|
|
329
|
+
def map_offset(self, offset: int) -> int | None:
|
|
330
|
+
if self.interpolation is None:
|
|
331
|
+
return None
|
|
332
|
+
|
|
333
|
+
if self.interpolation.source_start <= offset <= self.interpolation.source_end:
|
|
334
|
+
return self.interpolation.map_offset(offset)
|
|
335
|
+
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
def unmap_offset(self, offset: int) -> int | None:
|
|
339
|
+
if self.interpolation is None:
|
|
340
|
+
return None
|
|
341
|
+
|
|
342
|
+
if self.interpolation.transpiled_start <= offset <= self.interpolation.transpiled_end:
|
|
343
|
+
return self.interpolation.unmap_offset(offset)
|
|
227
344
|
|
|
228
345
|
return None
|
|
229
346
|
|
|
@@ -259,34 +376,37 @@ class ASTHTMLAttribute:
|
|
|
259
376
|
source_end: int = field(compare=False)
|
|
260
377
|
|
|
261
378
|
name: str
|
|
262
|
-
|
|
379
|
+
string_literal: str | None
|
|
263
380
|
interpolation: "ASTInterpolation | None"
|
|
264
381
|
|
|
265
382
|
transpiled_content: str = field(init=False)
|
|
266
383
|
transpiled_start: int = field(init=False)
|
|
267
384
|
transpiled_end: int = field(init=False)
|
|
268
385
|
|
|
269
|
-
|
|
270
|
-
__interpolation_template__: str = "{}={}"
|
|
386
|
+
__template__: str = '"{}":{}'
|
|
271
387
|
|
|
272
388
|
def transpile(self, transpiled_start: int) -> None:
|
|
273
389
|
self.transpiled_start = transpiled_start
|
|
274
390
|
|
|
275
|
-
if self.
|
|
276
|
-
self.transpiled_content = self.
|
|
391
|
+
if self.string_literal is not None:
|
|
392
|
+
self.transpiled_content = self.__template__.format(self.name, self.string_literal)
|
|
277
393
|
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
278
394
|
return
|
|
279
395
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
396
|
+
if self.interpolation is None:
|
|
397
|
+
self.transpiled_content = self.__template__.format(self.name, "None")
|
|
398
|
+
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
399
|
+
return
|
|
400
|
+
|
|
401
|
+
self.interpolation.transpile(self.transpiled_start + 1 + len(self.name) + 2) # " + name + ":
|
|
402
|
+
self.transpiled_content = self.__template__.format(self.name, self.interpolation.transpiled_content)
|
|
283
403
|
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
284
404
|
|
|
285
405
|
def map_offset(self, offset: int) -> int | None:
|
|
286
406
|
if self.interpolation is None:
|
|
287
407
|
return None
|
|
288
408
|
|
|
289
|
-
if self.interpolation.source_start
|
|
409
|
+
if self.interpolation.source_start <= offset <= self.interpolation.source_end:
|
|
290
410
|
return self.interpolation.map_offset(offset)
|
|
291
411
|
|
|
292
412
|
return None
|
|
@@ -295,7 +415,7 @@ class ASTHTMLAttribute:
|
|
|
295
415
|
if self.interpolation is None:
|
|
296
416
|
return None
|
|
297
417
|
|
|
298
|
-
if self.interpolation.transpiled_start
|
|
418
|
+
if self.interpolation.transpiled_start <= offset <= self.interpolation.transpiled_end:
|
|
299
419
|
return self.interpolation.unmap_offset(offset)
|
|
300
420
|
|
|
301
421
|
return None
|
|
@@ -344,14 +464,14 @@ class ASTInterpolation:
|
|
|
344
464
|
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
345
465
|
|
|
346
466
|
def map_offset(self, offset: int) -> int | None:
|
|
347
|
-
if self.source_start + 2 + self.leading_whitespace
|
|
467
|
+
if self.source_start + 2 + self.leading_whitespace <= offset <= self.source_end - 2 - self.trailing_whitespace:
|
|
348
468
|
specific_offset = offset - self.source_start - 2 - self.leading_whitespace
|
|
349
469
|
return self.transpiled_start + specific_offset
|
|
350
470
|
|
|
351
471
|
return None
|
|
352
472
|
|
|
353
473
|
def unmap_offset(self, offset: int) -> int | None:
|
|
354
|
-
if self.transpiled_start
|
|
474
|
+
if self.transpiled_start <= offset <= self.transpiled_end:
|
|
355
475
|
specific_offset = offset - self.transpiled_start
|
|
356
476
|
return self.source_start + specific_offset + 2 + self.leading_whitespace
|
|
357
477
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from fragments import grammar, transpiler
|
|
4
|
+
from fragments.source import Source
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_args() -> argparse.Namespace:
|
|
8
|
+
parser = argparse.ArgumentParser("fragments", description="Fragments transpilation CLI tool")
|
|
9
|
+
command_parser = parser.add_subparsers(required=True)
|
|
10
|
+
transpile_parser = command_parser.add_parser("transpile")
|
|
11
|
+
transpile_parser.add_argument("--input", type=str, required=True)
|
|
12
|
+
transpile_parser.set_defaults(func=transpile)
|
|
13
|
+
ast_parser = command_parser.add_parser("ast")
|
|
14
|
+
ast_parser.add_argument("--input", type=str, required=True)
|
|
15
|
+
ast_parser.set_defaults(func=ast)
|
|
16
|
+
return parser.parse_args()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def transpile(args: argparse.Namespace) -> None:
|
|
20
|
+
"""Transpile the specified file."""
|
|
21
|
+
with open(args.input, "r") as f:
|
|
22
|
+
source = f.read()
|
|
23
|
+
print(transpiler.transpile(source))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def ast(args: argparse.Namespace) -> None:
|
|
27
|
+
"""Print the AST of the specified file."""
|
|
28
|
+
with open(args.input, "r") as f:
|
|
29
|
+
source_string = f.read()
|
|
30
|
+
|
|
31
|
+
source = Source.from_string(source_string)
|
|
32
|
+
_, module_ast = grammar.expect_module(source)
|
|
33
|
+
module_ast.transpile()
|
|
34
|
+
print(module_ast)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def main():
|
|
38
|
+
args = parse_args()
|
|
39
|
+
assert hasattr(args, "func")
|
|
40
|
+
args.func(args)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
main()
|