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.
Files changed (80) hide show
  1. pulse/__init__.py +10 -24
  2. pulse/app.py +3 -25
  3. pulse/codegen/codegen.py +43 -88
  4. pulse/codegen/js.py +35 -5
  5. pulse/codegen/templates/route.py +341 -254
  6. pulse/form.py +1 -1
  7. pulse/helpers.py +40 -8
  8. pulse/hooks/core.py +2 -2
  9. pulse/hooks/effects.py +1 -1
  10. pulse/hooks/init.py +2 -1
  11. pulse/hooks/setup.py +1 -1
  12. pulse/hooks/stable.py +2 -2
  13. pulse/hooks/states.py +2 -2
  14. pulse/html/props.py +3 -2
  15. pulse/html/tags.py +135 -0
  16. pulse/html/tags.pyi +4 -0
  17. pulse/js/__init__.py +110 -0
  18. pulse/js/__init__.pyi +95 -0
  19. pulse/js/_types.py +297 -0
  20. pulse/js/array.py +253 -0
  21. pulse/js/console.py +47 -0
  22. pulse/js/date.py +113 -0
  23. pulse/js/document.py +138 -0
  24. pulse/js/error.py +139 -0
  25. pulse/js/json.py +62 -0
  26. pulse/js/map.py +84 -0
  27. pulse/js/math.py +66 -0
  28. pulse/js/navigator.py +76 -0
  29. pulse/js/number.py +54 -0
  30. pulse/js/object.py +173 -0
  31. pulse/js/promise.py +150 -0
  32. pulse/js/regexp.py +54 -0
  33. pulse/js/set.py +109 -0
  34. pulse/js/string.py +35 -0
  35. pulse/js/weakmap.py +50 -0
  36. pulse/js/weakset.py +45 -0
  37. pulse/js/window.py +199 -0
  38. pulse/messages.py +22 -3
  39. pulse/queries/client.py +7 -7
  40. pulse/queries/effect.py +16 -0
  41. pulse/queries/infinite_query.py +138 -29
  42. pulse/queries/mutation.py +1 -15
  43. pulse/queries/protocol.py +136 -0
  44. pulse/queries/query.py +610 -174
  45. pulse/queries/store.py +11 -14
  46. pulse/react_component.py +167 -14
  47. pulse/reactive.py +19 -1
  48. pulse/reactive_extensions.py +5 -5
  49. pulse/render_session.py +185 -59
  50. pulse/renderer.py +80 -158
  51. pulse/routing.py +1 -18
  52. pulse/transpiler/__init__.py +131 -0
  53. pulse/transpiler/builtins.py +731 -0
  54. pulse/transpiler/constants.py +110 -0
  55. pulse/transpiler/context.py +26 -0
  56. pulse/transpiler/errors.py +2 -0
  57. pulse/transpiler/function.py +250 -0
  58. pulse/transpiler/ids.py +16 -0
  59. pulse/transpiler/imports.py +409 -0
  60. pulse/transpiler/js_module.py +274 -0
  61. pulse/transpiler/modules/__init__.py +30 -0
  62. pulse/transpiler/modules/asyncio.py +38 -0
  63. pulse/transpiler/modules/json.py +20 -0
  64. pulse/transpiler/modules/math.py +320 -0
  65. pulse/transpiler/modules/re.py +466 -0
  66. pulse/transpiler/modules/tags.py +268 -0
  67. pulse/transpiler/modules/typing.py +59 -0
  68. pulse/transpiler/nodes.py +1216 -0
  69. pulse/transpiler/py_module.py +119 -0
  70. pulse/transpiler/transpiler.py +938 -0
  71. pulse/transpiler/utils.py +4 -0
  72. pulse/types/event_handler.py +3 -2
  73. pulse/vdom.py +212 -13
  74. {pulse_framework-0.1.44.dist-info → pulse_framework-0.1.47.dist-info}/METADATA +1 -1
  75. pulse_framework-0.1.47.dist-info/RECORD +119 -0
  76. pulse/codegen/imports.py +0 -204
  77. pulse/css.py +0 -155
  78. pulse_framework-0.1.44.dist-info/RECORD +0 -79
  79. {pulse_framework-0.1.44.dist-info → pulse_framework-0.1.47.dist-info}/WHEEL +0 -0
  80. {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
- class ReplaceOperation(TypedDict):
28
- type: Literal["replace"]
29
- path: str
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
- css_refs: set[str]
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.css_refs = set()
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.css_refs = renderer.css_refs
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.css_refs = renderer.css_refs
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.css_refs.clear()
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.css_refs: set[str] = set()
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 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
-
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
- self.css_refs.add(prop_path)
476
- if not isinstance(old_value, CssReference) or old_value != value:
477
- updated[key] = _css_ref_token(value)
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 += ".tsx"
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