pulse-framework 0.1.44__py3-none-any.whl → 0.1.47__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.
- pulse/__init__.py +10 -24
- pulse/app.py +3 -25
- pulse/codegen/codegen.py +43 -88
- pulse/codegen/js.py +35 -5
- pulse/codegen/templates/route.py +341 -254
- pulse/form.py +1 -1
- pulse/helpers.py +40 -8
- pulse/hooks/core.py +2 -2
- pulse/hooks/effects.py +1 -1
- pulse/hooks/init.py +2 -1
- pulse/hooks/setup.py +1 -1
- pulse/hooks/stable.py +2 -2
- pulse/hooks/states.py +2 -2
- pulse/html/props.py +3 -2
- pulse/html/tags.py +135 -0
- pulse/html/tags.pyi +4 -0
- pulse/js/__init__.py +110 -0
- pulse/js/__init__.pyi +95 -0
- pulse/js/_types.py +297 -0
- pulse/js/array.py +253 -0
- pulse/js/console.py +47 -0
- pulse/js/date.py +113 -0
- pulse/js/document.py +138 -0
- pulse/js/error.py +139 -0
- pulse/js/json.py +62 -0
- pulse/js/map.py +84 -0
- pulse/js/math.py +66 -0
- pulse/js/navigator.py +76 -0
- pulse/js/number.py +54 -0
- pulse/js/object.py +173 -0
- pulse/js/promise.py +150 -0
- pulse/js/regexp.py +54 -0
- pulse/js/set.py +109 -0
- pulse/js/string.py +35 -0
- pulse/js/weakmap.py +50 -0
- pulse/js/weakset.py +45 -0
- pulse/js/window.py +199 -0
- pulse/messages.py +22 -3
- pulse/queries/client.py +7 -7
- pulse/queries/effect.py +16 -0
- pulse/queries/infinite_query.py +138 -29
- pulse/queries/mutation.py +1 -15
- pulse/queries/protocol.py +136 -0
- pulse/queries/query.py +610 -174
- pulse/queries/store.py +11 -14
- pulse/react_component.py +167 -14
- pulse/reactive.py +19 -1
- pulse/reactive_extensions.py +5 -5
- pulse/render_session.py +185 -59
- pulse/renderer.py +80 -158
- pulse/routing.py +1 -18
- pulse/transpiler/__init__.py +131 -0
- pulse/transpiler/builtins.py +731 -0
- pulse/transpiler/constants.py +110 -0
- pulse/transpiler/context.py +26 -0
- pulse/transpiler/errors.py +2 -0
- pulse/transpiler/function.py +250 -0
- pulse/transpiler/ids.py +16 -0
- pulse/transpiler/imports.py +409 -0
- pulse/transpiler/js_module.py +274 -0
- pulse/transpiler/modules/__init__.py +30 -0
- pulse/transpiler/modules/asyncio.py +38 -0
- pulse/transpiler/modules/json.py +20 -0
- pulse/transpiler/modules/math.py +320 -0
- pulse/transpiler/modules/re.py +466 -0
- pulse/transpiler/modules/tags.py +268 -0
- pulse/transpiler/modules/typing.py +59 -0
- pulse/transpiler/nodes.py +1216 -0
- pulse/transpiler/py_module.py +119 -0
- pulse/transpiler/transpiler.py +938 -0
- pulse/transpiler/utils.py +4 -0
- pulse/types/event_handler.py +3 -2
- pulse/vdom.py +212 -13
- {pulse_framework-0.1.44.dist-info → pulse_framework-0.1.47.dist-info}/METADATA +1 -1
- pulse_framework-0.1.47.dist-info/RECORD +119 -0
- pulse/codegen/imports.py +0 -204
- pulse/css.py +0 -155
- pulse_framework-0.1.44.dist-info/RECORD +0 -79
- {pulse_framework-0.1.44.dist-info → pulse_framework-0.1.47.dist-info}/WHEEL +0 -0
- {pulse_framework-0.1.44.dist-info → pulse_framework-0.1.47.dist-info}/entry_points.txt +0 -0
pulse/renderer.py
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
from collections.abc import Callable, Sequence
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import
|
|
5
|
-
Any,
|
|
6
|
-
Literal,
|
|
7
|
-
NamedTuple,
|
|
8
|
-
TypeAlias,
|
|
9
|
-
TypedDict,
|
|
10
|
-
cast,
|
|
11
|
-
)
|
|
4
|
+
from typing import Any, NamedTuple, TypeAlias, cast
|
|
12
5
|
|
|
13
|
-
from pulse.css import CssReference
|
|
14
6
|
from pulse.helpers import values_equal
|
|
7
|
+
from pulse.transpiler.context import interpreted_mode
|
|
8
|
+
from pulse.transpiler.imports import Import
|
|
9
|
+
from pulse.transpiler.nodes import JSExpr
|
|
15
10
|
from pulse.vdom import (
|
|
16
11
|
VDOM,
|
|
17
12
|
Callback,
|
|
@@ -19,78 +14,32 @@ from pulse.vdom import (
|
|
|
19
14
|
ComponentNode,
|
|
20
15
|
Element,
|
|
21
16
|
Node,
|
|
17
|
+
PathDelta,
|
|
22
18
|
Props,
|
|
19
|
+
ReconciliationOperation,
|
|
20
|
+
ReplaceOperation,
|
|
21
|
+
UpdateCallbacksOperation,
|
|
22
|
+
UpdateJsExprPathsOperation,
|
|
23
|
+
UpdatePropsDelta,
|
|
24
|
+
UpdatePropsOperation,
|
|
25
|
+
UpdateRenderPropsOperation,
|
|
23
26
|
VDOMNode,
|
|
27
|
+
VDOMOperation,
|
|
24
28
|
)
|
|
25
29
|
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
data: VDOM
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# This payload makes it easy for the client to rebuild an array of React nodes
|
|
34
|
-
# from the previous children array:
|
|
35
|
-
# - Allocate array of size N
|
|
36
|
-
# - For i in 0..N-1, check the following scenarios
|
|
37
|
-
# - i matches the next index in `new` -> use provided tree
|
|
38
|
-
# - i matches the next index in `reuse` -> reuse previous child
|
|
39
|
-
# - otherwise, reuse the element at the same index
|
|
40
|
-
class ReconciliationOperation(TypedDict):
|
|
41
|
-
type: Literal["reconciliation"]
|
|
42
|
-
path: str
|
|
43
|
-
N: int
|
|
44
|
-
new: tuple[list[int], list[VDOM]]
|
|
45
|
-
reuse: tuple[list[int], list[int]]
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class UpdatePropsDelta(TypedDict, total=False):
|
|
49
|
-
# Only send changed/new keys under `set` and removed keys under `remove`
|
|
50
|
-
set: Props
|
|
51
|
-
remove: list[str]
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class UpdatePropsOperation(TypedDict):
|
|
55
|
-
type: Literal["update_props"]
|
|
56
|
-
path: str
|
|
57
|
-
data: UpdatePropsDelta
|
|
58
|
-
|
|
31
|
+
def is_jsexpr(value: object) -> bool:
|
|
32
|
+
"""Check if a value is a JSExpr or Import."""
|
|
33
|
+
return isinstance(value, (JSExpr, Import))
|
|
59
34
|
|
|
60
|
-
class PathDelta(TypedDict, total=False):
|
|
61
|
-
add: list[str]
|
|
62
|
-
remove: list[str]
|
|
63
35
|
|
|
36
|
+
def emit_jsexpr(value: "JSExpr | Import") -> str:
|
|
37
|
+
"""Emit a JSExpr in interpreted mode (for client-side evaluation)."""
|
|
38
|
+
with interpreted_mode():
|
|
39
|
+
if isinstance(value, Import):
|
|
40
|
+
return value.emit()
|
|
41
|
+
return value.emit()
|
|
64
42
|
|
|
65
|
-
class UpdateCallbacksOperation(TypedDict):
|
|
66
|
-
type: Literal["update_callbacks"]
|
|
67
|
-
path: str
|
|
68
|
-
data: PathDelta
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
class UpdateCssRefsOperation(TypedDict):
|
|
72
|
-
type: Literal["update_css_refs"]
|
|
73
|
-
path: str
|
|
74
|
-
data: PathDelta
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class UpdateRenderPropsOperation(TypedDict):
|
|
78
|
-
type: Literal["update_render_props"]
|
|
79
|
-
path: str
|
|
80
|
-
data: PathDelta
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
VDOMOperation: TypeAlias = (
|
|
84
|
-
# InsertOperation,
|
|
85
|
-
# RemoveOperation,
|
|
86
|
-
ReplaceOperation
|
|
87
|
-
| UpdatePropsOperation
|
|
88
|
-
# | MoveOperation,
|
|
89
|
-
| ReconciliationOperation
|
|
90
|
-
| UpdateCallbacksOperation
|
|
91
|
-
| UpdateCssRefsOperation
|
|
92
|
-
| UpdateRenderPropsOperation
|
|
93
|
-
)
|
|
94
43
|
|
|
95
44
|
RenderPath: TypeAlias = str
|
|
96
45
|
|
|
@@ -99,13 +48,13 @@ class RenderTree:
|
|
|
99
48
|
root: Element
|
|
100
49
|
callbacks: Callbacks
|
|
101
50
|
render_props: set[str]
|
|
102
|
-
|
|
51
|
+
jsexpr_paths: set[str] # paths containing JS expressions
|
|
103
52
|
|
|
104
53
|
def __init__(self, root: Element) -> None:
|
|
105
54
|
self.root = root
|
|
106
55
|
self.callbacks = {}
|
|
107
56
|
self.render_props = set()
|
|
108
|
-
self.
|
|
57
|
+
self.jsexpr_paths = set()
|
|
109
58
|
self.normalized: Element | None = None
|
|
110
59
|
|
|
111
60
|
def render(self) -> VDOM:
|
|
@@ -114,7 +63,7 @@ class RenderTree:
|
|
|
114
63
|
self.root = normalized
|
|
115
64
|
self.callbacks = renderer.callbacks
|
|
116
65
|
self.render_props = renderer.render_props
|
|
117
|
-
self.
|
|
66
|
+
self.jsexpr_paths = renderer.jsexpr_paths
|
|
118
67
|
self.normalized = normalized
|
|
119
68
|
return vdom
|
|
120
69
|
|
|
@@ -135,23 +84,8 @@ class RenderTree:
|
|
|
135
84
|
render_props_add = sorted(render_props_next - render_props_prev)
|
|
136
85
|
render_props_remove = sorted(render_props_prev - render_props_next)
|
|
137
86
|
|
|
138
|
-
css_prev = self.css_refs
|
|
139
|
-
css_next = renderer.css_refs
|
|
140
|
-
css_add = sorted(css_next - css_prev)
|
|
141
|
-
css_remove = sorted(css_prev - css_next)
|
|
142
|
-
|
|
143
87
|
prefix: list[VDOMOperation] = []
|
|
144
88
|
|
|
145
|
-
if css_add or css_remove:
|
|
146
|
-
css_delta: PathDelta = {}
|
|
147
|
-
if css_add:
|
|
148
|
-
css_delta["add"] = css_add
|
|
149
|
-
if css_remove:
|
|
150
|
-
css_delta["remove"] = css_remove
|
|
151
|
-
prefix.append(
|
|
152
|
-
UpdateCssRefsOperation(type="update_css_refs", path="", data=css_delta)
|
|
153
|
-
)
|
|
154
|
-
|
|
155
89
|
if callback_add or callback_remove:
|
|
156
90
|
callback_delta: PathDelta = {}
|
|
157
91
|
if callback_add:
|
|
@@ -176,11 +110,27 @@ class RenderTree:
|
|
|
176
110
|
)
|
|
177
111
|
)
|
|
178
112
|
|
|
113
|
+
jsexpr_prev = self.jsexpr_paths
|
|
114
|
+
jsexpr_next = renderer.jsexpr_paths
|
|
115
|
+
jsexpr_add = sorted(jsexpr_next - jsexpr_prev)
|
|
116
|
+
jsexpr_remove = sorted(jsexpr_prev - jsexpr_next)
|
|
117
|
+
if jsexpr_add or jsexpr_remove:
|
|
118
|
+
jsexpr_delta: PathDelta = {}
|
|
119
|
+
if jsexpr_add:
|
|
120
|
+
jsexpr_delta["add"] = jsexpr_add
|
|
121
|
+
if jsexpr_remove:
|
|
122
|
+
jsexpr_delta["remove"] = jsexpr_remove
|
|
123
|
+
prefix.append(
|
|
124
|
+
UpdateJsExprPathsOperation(
|
|
125
|
+
type="update_jsexpr_paths", path="", data=jsexpr_delta
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
|
|
179
129
|
ops = prefix + renderer.operations if prefix else renderer.operations
|
|
180
130
|
|
|
181
131
|
self.callbacks = renderer.callbacks
|
|
182
132
|
self.render_props = renderer.render_props
|
|
183
|
-
self.
|
|
133
|
+
self.jsexpr_paths = renderer.jsexpr_paths
|
|
184
134
|
self.normalized = normalized
|
|
185
135
|
self.root = normalized
|
|
186
136
|
|
|
@@ -192,7 +142,11 @@ class RenderTree:
|
|
|
192
142
|
self.normalized = None
|
|
193
143
|
self.callbacks.clear()
|
|
194
144
|
self.render_props.clear()
|
|
195
|
-
self.
|
|
145
|
+
self.jsexpr_paths.clear()
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# Prefix for JSExpr values - code is embedded after the colon
|
|
149
|
+
JSEXPR_PREFIX = "$js:"
|
|
196
150
|
|
|
197
151
|
|
|
198
152
|
@dataclass(slots=True)
|
|
@@ -214,7 +168,7 @@ class Renderer:
|
|
|
214
168
|
def __init__(self) -> None:
|
|
215
169
|
self.callbacks: Callbacks = {}
|
|
216
170
|
self.render_props: set[str] = set()
|
|
217
|
-
self.
|
|
171
|
+
self.jsexpr_paths: set[str] = set()
|
|
218
172
|
self.operations: list[VDOMOperation] = []
|
|
219
173
|
|
|
220
174
|
# ------------------------------------------------------------------
|
|
@@ -226,6 +180,13 @@ class Renderer:
|
|
|
226
180
|
return self.render_component(node, path)
|
|
227
181
|
if isinstance(node, Node):
|
|
228
182
|
return self.render_node(node, path)
|
|
183
|
+
# Handle JSExpr as children - emit JS code with $js: prefix
|
|
184
|
+
if is_jsexpr(node):
|
|
185
|
+
# Safe cast: is_jsexpr() ensures node is JSExpr | Import
|
|
186
|
+
node_as_jsexpr = cast("JSExpr | Import", cast(object, node))
|
|
187
|
+
js_code = emit_jsexpr(node_as_jsexpr)
|
|
188
|
+
self.jsexpr_paths.add(path)
|
|
189
|
+
return f"{JSEXPR_PREFIX}{js_code}", cast(Element, node)
|
|
229
190
|
return node, node
|
|
230
191
|
|
|
231
192
|
def render_component(
|
|
@@ -453,28 +414,23 @@ class Renderer:
|
|
|
453
414
|
old_value = previous.get(key)
|
|
454
415
|
prop_path = join_path(path, key)
|
|
455
416
|
|
|
456
|
-
if
|
|
457
|
-
if isinstance(old_value, (Node, ComponentNode)):
|
|
458
|
-
unmount_element(old_value)
|
|
459
|
-
if normalized is None:
|
|
460
|
-
normalized = current.copy()
|
|
461
|
-
normalized[key] = "$cb"
|
|
462
|
-
register_callback(
|
|
463
|
-
self.callbacks, prop_path, cast(Callable[..., Any], value)
|
|
464
|
-
)
|
|
465
|
-
if old_value != "$cb":
|
|
466
|
-
updated[key] = "$cb"
|
|
467
|
-
continue
|
|
468
|
-
|
|
469
|
-
if isinstance(value, CssReference):
|
|
417
|
+
if is_jsexpr(value):
|
|
470
418
|
if isinstance(old_value, (Node, ComponentNode)):
|
|
471
419
|
unmount_element(old_value)
|
|
472
420
|
if normalized is None:
|
|
473
421
|
normalized = current.copy()
|
|
474
422
|
normalized[key] = value
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
423
|
+
# Emit the JSExpr with $js: prefix - code is embedded in the value
|
|
424
|
+
js_code = emit_jsexpr(cast("JSExpr | Import", value))
|
|
425
|
+
self.jsexpr_paths.add(prop_path)
|
|
426
|
+
js_value = f"{JSEXPR_PREFIX}{js_code}"
|
|
427
|
+
old_js_code = (
|
|
428
|
+
emit_jsexpr(cast("JSExpr | Import", old_value))
|
|
429
|
+
if is_jsexpr(old_value)
|
|
430
|
+
else None
|
|
431
|
+
)
|
|
432
|
+
if old_js_code != js_code:
|
|
433
|
+
updated[key] = js_value
|
|
478
434
|
continue
|
|
479
435
|
|
|
480
436
|
if isinstance(value, (Node, ComponentNode)):
|
|
@@ -497,6 +453,19 @@ class Renderer:
|
|
|
497
453
|
updated[key] = vdom_value
|
|
498
454
|
continue
|
|
499
455
|
|
|
456
|
+
if callable(value):
|
|
457
|
+
if isinstance(old_value, (Node, ComponentNode)):
|
|
458
|
+
unmount_element(old_value)
|
|
459
|
+
if normalized is None:
|
|
460
|
+
normalized = current.copy()
|
|
461
|
+
normalized[key] = "$cb"
|
|
462
|
+
register_callback(
|
|
463
|
+
self.callbacks, prop_path, cast(Callable[..., Any], value)
|
|
464
|
+
)
|
|
465
|
+
if old_value != "$cb":
|
|
466
|
+
updated[key] = "$cb"
|
|
467
|
+
continue
|
|
468
|
+
|
|
500
469
|
if isinstance(old_value, (Node, ComponentNode)):
|
|
501
470
|
unmount_element(old_value)
|
|
502
471
|
|
|
@@ -527,21 +496,6 @@ class Renderer:
|
|
|
527
496
|
unmount_element(node)
|
|
528
497
|
|
|
529
498
|
|
|
530
|
-
def extract_key(element: Element) -> str | None:
|
|
531
|
-
if isinstance(element, ComponentNode):
|
|
532
|
-
return element.key
|
|
533
|
-
if isinstance(element, Node):
|
|
534
|
-
return element.key
|
|
535
|
-
return None
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
def child_key(element: Element, index: int) -> str:
|
|
539
|
-
key = extract_key(element)
|
|
540
|
-
if key is not None:
|
|
541
|
-
return key
|
|
542
|
-
return f"__idx__{index}"
|
|
543
|
-
|
|
544
|
-
|
|
545
499
|
def normalize_children(children: Sequence[Element] | None) -> list[Element]:
|
|
546
500
|
if not children:
|
|
547
501
|
return []
|
|
@@ -573,38 +527,6 @@ def same_node(left: Element, right: Element) -> bool:
|
|
|
573
527
|
return False
|
|
574
528
|
|
|
575
529
|
|
|
576
|
-
def lis(seq: list[int]) -> list[int]:
|
|
577
|
-
if not seq:
|
|
578
|
-
return []
|
|
579
|
-
tails: list[int] = []
|
|
580
|
-
prev: list[int] = [-1] * len(seq)
|
|
581
|
-
for i, v in enumerate(seq):
|
|
582
|
-
lo, hi = 0, len(tails)
|
|
583
|
-
while lo < hi:
|
|
584
|
-
mid = (lo + hi) // 2
|
|
585
|
-
if seq[tails[mid]] < v:
|
|
586
|
-
lo = mid + 1
|
|
587
|
-
else:
|
|
588
|
-
hi = mid
|
|
589
|
-
if lo > 0:
|
|
590
|
-
prev[i] = tails[lo - 1]
|
|
591
|
-
if lo == len(tails):
|
|
592
|
-
tails.append(i)
|
|
593
|
-
else:
|
|
594
|
-
tails[lo] = i
|
|
595
|
-
lis_indices: list[int] = []
|
|
596
|
-
k = tails[-1] if tails else -1
|
|
597
|
-
while k != -1:
|
|
598
|
-
lis_indices.append(k)
|
|
599
|
-
k = prev[k]
|
|
600
|
-
lis_indices.reverse()
|
|
601
|
-
return lis_indices
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
def _css_ref_token(ref: CssReference) -> str:
|
|
605
|
-
return f"{ref.module.id}:{ref.name}"
|
|
606
|
-
|
|
607
|
-
|
|
608
530
|
def unmount_element(element: Element) -> None:
|
|
609
531
|
if isinstance(element, ComponentNode):
|
|
610
532
|
if element.contents is not None:
|
pulse/routing.py
CHANGED
|
@@ -3,7 +3,6 @@ from collections.abc import Sequence
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from typing import TypedDict, cast, override
|
|
5
5
|
|
|
6
|
-
from pulse.css import CssImport, CssModule
|
|
7
6
|
from pulse.env import env
|
|
8
7
|
from pulse.react_component import ReactComponent
|
|
9
8
|
from pulse.reactive_extensions import ReactiveDict
|
|
@@ -160,8 +159,6 @@ class Route:
|
|
|
160
159
|
render: Component[[]]
|
|
161
160
|
children: Sequence["Route | Layout"]
|
|
162
161
|
components: Sequence[ReactComponent[...]] | None
|
|
163
|
-
css_modules: Sequence[CssModule] | None
|
|
164
|
-
css_imports: Sequence[CssImport] | None
|
|
165
162
|
is_index: bool
|
|
166
163
|
is_dynamic: bool
|
|
167
164
|
dev: bool
|
|
@@ -172,8 +169,6 @@ class Route:
|
|
|
172
169
|
render: Component[[]],
|
|
173
170
|
children: "Sequence[Route | Layout] | None" = None,
|
|
174
171
|
components: "Sequence[ReactComponent[...]] | None" = None,
|
|
175
|
-
css_modules: Sequence[CssModule] | None = None,
|
|
176
|
-
css_imports: Sequence[CssImport] | None = None,
|
|
177
172
|
dev: bool = False,
|
|
178
173
|
):
|
|
179
174
|
self.path = ensure_relative_path(path)
|
|
@@ -182,8 +177,6 @@ class Route:
|
|
|
182
177
|
self.render = render
|
|
183
178
|
self.children = children or []
|
|
184
179
|
self.components = components
|
|
185
|
-
self.css_modules = css_modules
|
|
186
|
-
self.css_imports = css_imports
|
|
187
180
|
self.dev = dev
|
|
188
181
|
self.parent: Route | Layout | None = None
|
|
189
182
|
|
|
@@ -208,7 +201,7 @@ class Route:
|
|
|
208
201
|
path = "/".join(self._path_list(include_layouts=False))
|
|
209
202
|
if self.is_index:
|
|
210
203
|
path += "index"
|
|
211
|
-
path += ".
|
|
204
|
+
path += ".jsx"
|
|
212
205
|
# Replace Windows-invalid characters in filenames
|
|
213
206
|
return _sanitize_filename(path)
|
|
214
207
|
|
|
@@ -257,8 +250,6 @@ class Layout:
|
|
|
257
250
|
render: Component[...]
|
|
258
251
|
children: Sequence["Route | Layout"]
|
|
259
252
|
components: Sequence[ReactComponent[...]] | None
|
|
260
|
-
css_modules: Sequence[CssModule] | None
|
|
261
|
-
css_imports: Sequence[CssImport] | None
|
|
262
253
|
dev: bool
|
|
263
254
|
|
|
264
255
|
def __init__(
|
|
@@ -266,15 +257,11 @@ class Layout:
|
|
|
266
257
|
render: "Component[...]",
|
|
267
258
|
children: "Sequence[Route | Layout] | None" = None,
|
|
268
259
|
components: "Sequence[ReactComponent[...]] | None" = None,
|
|
269
|
-
css_modules: Sequence[CssModule] | None = None,
|
|
270
|
-
css_imports: Sequence[CssImport] | None = None,
|
|
271
260
|
dev: bool = False,
|
|
272
261
|
):
|
|
273
262
|
self.render = render
|
|
274
263
|
self.children = children or []
|
|
275
264
|
self.components = components
|
|
276
|
-
self.css_modules = css_modules
|
|
277
|
-
self.css_imports = css_imports
|
|
278
265
|
self.dev = dev
|
|
279
266
|
self.parent: Route | Layout | None = None
|
|
280
267
|
# 1-based sibling index assigned by RouteTree at each level
|
|
@@ -366,8 +353,6 @@ def filter_dev_routes(routes: Sequence[Route | Layout]) -> list[Route | Layout]:
|
|
|
366
353
|
render=route.render,
|
|
367
354
|
children=filtered_children,
|
|
368
355
|
components=route.components,
|
|
369
|
-
css_modules=route.css_modules,
|
|
370
|
-
css_imports=route.css_imports,
|
|
371
356
|
dev=route.dev,
|
|
372
357
|
)
|
|
373
358
|
else: # Layout
|
|
@@ -375,8 +360,6 @@ def filter_dev_routes(routes: Sequence[Route | Layout]) -> list[Route | Layout]:
|
|
|
375
360
|
render=route.render,
|
|
376
361
|
children=filtered_children,
|
|
377
362
|
components=route.components,
|
|
378
|
-
css_modules=route.css_modules,
|
|
379
|
-
css_imports=route.css_imports,
|
|
380
363
|
dev=route.dev,
|
|
381
364
|
)
|
|
382
365
|
filtered.append(filtered_route)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""Python -> JavaScript transpiler system.
|
|
2
|
+
|
|
3
|
+
This module provides the full transpilation API for converting Python functions
|
|
4
|
+
to JavaScript. For basic usage, use the exports from the main `pulse` module:
|
|
5
|
+
|
|
6
|
+
from pulse import javascript, Import, CssImport, import_js
|
|
7
|
+
|
|
8
|
+
For advanced use cases (custom transpilers, AST manipulation, module registration),
|
|
9
|
+
import from this module:
|
|
10
|
+
|
|
11
|
+
from pulse.transpiler import JSExpr, JsTranspiler, register_module, ...
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# Core types
|
|
15
|
+
# Builtins system
|
|
16
|
+
from pulse.transpiler.builtins import ALL_METHODS as ALL_METHODS
|
|
17
|
+
from pulse.transpiler.builtins import BUILTINS as BUILTINS
|
|
18
|
+
from pulse.transpiler.builtins import DICT_METHODS as DICT_METHODS
|
|
19
|
+
from pulse.transpiler.builtins import LIST_METHODS as LIST_METHODS
|
|
20
|
+
from pulse.transpiler.builtins import METHOD_CLASSES as METHOD_CLASSES
|
|
21
|
+
from pulse.transpiler.builtins import SET_METHODS as SET_METHODS
|
|
22
|
+
from pulse.transpiler.builtins import STR_METHODS as STR_METHODS
|
|
23
|
+
from pulse.transpiler.builtins import BuiltinMethods as BuiltinMethods
|
|
24
|
+
from pulse.transpiler.builtins import DictMethods as DictMethods
|
|
25
|
+
from pulse.transpiler.builtins import ListMethods as ListMethods
|
|
26
|
+
from pulse.transpiler.builtins import SetMethods as SetMethods
|
|
27
|
+
from pulse.transpiler.builtins import StringMethods as StringMethods
|
|
28
|
+
from pulse.transpiler.builtins import emit_method as emit_method
|
|
29
|
+
|
|
30
|
+
# Constants system
|
|
31
|
+
from pulse.transpiler.constants import CONSTANTS_CACHE as CONSTANTS_CACHE
|
|
32
|
+
from pulse.transpiler.constants import JsConstant as JsConstant
|
|
33
|
+
from pulse.transpiler.constants import JsPrimitive as JsPrimitive
|
|
34
|
+
from pulse.transpiler.constants import JsValue as JsValue
|
|
35
|
+
from pulse.transpiler.constants import JsVar as JsVar
|
|
36
|
+
from pulse.transpiler.constants import const_to_js as const_to_js
|
|
37
|
+
from pulse.transpiler.constants import jsify as jsify
|
|
38
|
+
|
|
39
|
+
# Context
|
|
40
|
+
from pulse.transpiler.context import interpreted_mode as interpreted_mode
|
|
41
|
+
from pulse.transpiler.context import is_interpreted_mode as is_interpreted_mode
|
|
42
|
+
from pulse.transpiler.errors import JSCompilationError as JSCompilationError
|
|
43
|
+
|
|
44
|
+
# Function system
|
|
45
|
+
from pulse.transpiler.function import FUNCTION_CACHE as FUNCTION_CACHE
|
|
46
|
+
from pulse.transpiler.function import JsFunction as JsFunction
|
|
47
|
+
from pulse.transpiler.function import javascript as javascript
|
|
48
|
+
|
|
49
|
+
# Utilities
|
|
50
|
+
from pulse.transpiler.ids import generate_id as generate_id
|
|
51
|
+
from pulse.transpiler.ids import reset_id_counter as reset_id_counter
|
|
52
|
+
from pulse.transpiler.imports import CssImport as CssImport
|
|
53
|
+
from pulse.transpiler.imports import Import as Import
|
|
54
|
+
|
|
55
|
+
# Import system
|
|
56
|
+
from pulse.transpiler.imports import clear_import_registry as clear_import_registry
|
|
57
|
+
from pulse.transpiler.imports import import_js as import_js
|
|
58
|
+
from pulse.transpiler.imports import registered_imports as registered_imports
|
|
59
|
+
|
|
60
|
+
# Module registration - JS modules
|
|
61
|
+
from pulse.transpiler.js_module import JS_MODULES as JS_MODULES
|
|
62
|
+
from pulse.transpiler.js_module import JsModule as JsModule
|
|
63
|
+
from pulse.transpiler.js_module import register_js_module as register_js_module
|
|
64
|
+
|
|
65
|
+
# JS AST Utilities
|
|
66
|
+
from pulse.transpiler.nodes import ALLOWED_BINOPS as ALLOWED_BINOPS
|
|
67
|
+
from pulse.transpiler.nodes import ALLOWED_CMPOPS as ALLOWED_CMPOPS
|
|
68
|
+
from pulse.transpiler.nodes import ALLOWED_UNOPS as ALLOWED_UNOPS
|
|
69
|
+
from pulse.transpiler.nodes import JSEXPR_REGISTRY as JSEXPR_REGISTRY
|
|
70
|
+
|
|
71
|
+
# JS AST Nodes - Expressions
|
|
72
|
+
from pulse.transpiler.nodes import JSArray as JSArray
|
|
73
|
+
from pulse.transpiler.nodes import JSArrowFunction as JSArrowFunction
|
|
74
|
+
|
|
75
|
+
# JS AST Nodes - Statements
|
|
76
|
+
from pulse.transpiler.nodes import JSAssign as JSAssign
|
|
77
|
+
from pulse.transpiler.nodes import JSAugAssign as JSAugAssign
|
|
78
|
+
from pulse.transpiler.nodes import JSBinary as JSBinary
|
|
79
|
+
from pulse.transpiler.nodes import JSBlock as JSBlock
|
|
80
|
+
from pulse.transpiler.nodes import JSBoolean as JSBoolean
|
|
81
|
+
from pulse.transpiler.nodes import JSBreak as JSBreak
|
|
82
|
+
from pulse.transpiler.nodes import JSCall as JSCall
|
|
83
|
+
from pulse.transpiler.nodes import JSComma as JSComma
|
|
84
|
+
from pulse.transpiler.nodes import JSComputedProp as JSComputedProp
|
|
85
|
+
from pulse.transpiler.nodes import JSConstAssign as JSConstAssign
|
|
86
|
+
from pulse.transpiler.nodes import JSContinue as JSContinue
|
|
87
|
+
from pulse.transpiler.nodes import JSExpr as JSExpr
|
|
88
|
+
from pulse.transpiler.nodes import JSForOf as JSForOf
|
|
89
|
+
from pulse.transpiler.nodes import JSFunctionDef as JSFunctionDef
|
|
90
|
+
from pulse.transpiler.nodes import JSIdentifier as JSIdentifier
|
|
91
|
+
from pulse.transpiler.nodes import JSIf as JSIf
|
|
92
|
+
|
|
93
|
+
# JS AST Nodes - JSX
|
|
94
|
+
from pulse.transpiler.nodes import JSImport as JSImport
|
|
95
|
+
from pulse.transpiler.nodes import JSLogicalChain as JSLogicalChain
|
|
96
|
+
from pulse.transpiler.nodes import JSMember as JSMember
|
|
97
|
+
from pulse.transpiler.nodes import JSMemberCall as JSMemberCall
|
|
98
|
+
from pulse.transpiler.nodes import JSMultiStmt as JSMultiStmt
|
|
99
|
+
from pulse.transpiler.nodes import JSNew as JSNew
|
|
100
|
+
from pulse.transpiler.nodes import JSNode as JSNode
|
|
101
|
+
from pulse.transpiler.nodes import JSNull as JSNull
|
|
102
|
+
from pulse.transpiler.nodes import JSNumber as JSNumber
|
|
103
|
+
from pulse.transpiler.nodes import JSObjectExpr as JSObjectExpr
|
|
104
|
+
from pulse.transpiler.nodes import JSProp as JSProp
|
|
105
|
+
from pulse.transpiler.nodes import JSRaw as JSRaw
|
|
106
|
+
from pulse.transpiler.nodes import JSReturn as JSReturn
|
|
107
|
+
from pulse.transpiler.nodes import JSSingleStmt as JSSingleStmt
|
|
108
|
+
from pulse.transpiler.nodes import JSSpread as JSSpread
|
|
109
|
+
from pulse.transpiler.nodes import JSStmt as JSStmt
|
|
110
|
+
from pulse.transpiler.nodes import JSString as JSString
|
|
111
|
+
from pulse.transpiler.nodes import JSSubscript as JSSubscript
|
|
112
|
+
from pulse.transpiler.nodes import JSTemplate as JSTemplate
|
|
113
|
+
from pulse.transpiler.nodes import JSTertiary as JSTertiary
|
|
114
|
+
from pulse.transpiler.nodes import JSTransformer as JSTransformer
|
|
115
|
+
from pulse.transpiler.nodes import JSUnary as JSUnary
|
|
116
|
+
from pulse.transpiler.nodes import JSUndefined as JSUndefined
|
|
117
|
+
from pulse.transpiler.nodes import JSWhile as JSWhile
|
|
118
|
+
from pulse.transpiler.nodes import JSXElement as JSXElement
|
|
119
|
+
from pulse.transpiler.nodes import JSXFragment as JSXFragment
|
|
120
|
+
from pulse.transpiler.nodes import JSXProp as JSXProp
|
|
121
|
+
from pulse.transpiler.nodes import JSXSpreadProp as JSXSpreadProp
|
|
122
|
+
from pulse.transpiler.nodes import is_primary as is_primary
|
|
123
|
+
|
|
124
|
+
# Module registration - Python modules
|
|
125
|
+
from pulse.transpiler.py_module import PY_MODULES as PY_MODULES
|
|
126
|
+
from pulse.transpiler.py_module import PyModule as PyModule
|
|
127
|
+
from pulse.transpiler.py_module import PyModuleExpr as PyModuleExpr
|
|
128
|
+
from pulse.transpiler.py_module import register_module as register_module
|
|
129
|
+
|
|
130
|
+
# Transpiler
|
|
131
|
+
from pulse.transpiler.transpiler import JsTranspiler as JsTranspiler
|