pulse-framework 0.1.46__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 +9 -23
- pulse/app.py +2 -24
- 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/react_component.py +167 -14
- pulse/reactive_extensions.py +5 -5
- pulse/render_session.py +144 -34
- pulse/renderer.py +80 -115
- 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/vdom.py +112 -6
- {pulse_framework-0.1.46.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.46.dist-info/RECORD +0 -80
- {pulse_framework-0.1.46.dist-info → pulse_framework-0.1.47.dist-info}/WHEEL +0 -0
- {pulse_framework-0.1.46.dist-info → pulse_framework-0.1.47.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Python module transpilation system for javascript_v2.
|
|
2
|
+
|
|
3
|
+
Provides infrastructure for mapping Python modules (like `math`) to JavaScript equivalents.
|
|
4
|
+
For direct JavaScript module bindings, use the pulse.js.* module system instead.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from types import ModuleType
|
|
12
|
+
from typing import Any, TypeAlias, cast, override
|
|
13
|
+
|
|
14
|
+
from pulse.transpiler.errors import JSCompilationError
|
|
15
|
+
from pulse.transpiler.nodes import JSExpr, JSTransformer
|
|
16
|
+
|
|
17
|
+
# Type alias for module transpilers - either a PyModule class or a dict
|
|
18
|
+
# The dict can contain JSExpr or Callable[..., JSExpr] during construction,
|
|
19
|
+
# but will be normalized to only JSExpr before storage
|
|
20
|
+
PyModuleTranspiler: TypeAlias = dict[str, JSExpr]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class PyModuleExpr(JSExpr):
|
|
25
|
+
"""JSExpr for a Python module imported as a whole (e.g., `import math`).
|
|
26
|
+
|
|
27
|
+
Holds a transpiler dict mapping attribute names to JSExpr.
|
|
28
|
+
Attribute access looks up the attr in the dict and returns the result.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
transpiler: dict[str, JSExpr]
|
|
32
|
+
|
|
33
|
+
@override
|
|
34
|
+
def emit(self) -> str:
|
|
35
|
+
raise JSCompilationError("PyModuleExpr cannot be emitted directly")
|
|
36
|
+
|
|
37
|
+
@override
|
|
38
|
+
def emit_call(self, args: list[Any], kwargs: dict[str, Any]) -> JSExpr:
|
|
39
|
+
raise JSCompilationError("PyModuleExpr cannot be called directly")
|
|
40
|
+
|
|
41
|
+
@override
|
|
42
|
+
def emit_subscript(self, indices: list[Any]) -> JSExpr:
|
|
43
|
+
raise JSCompilationError("PyModuleExpr cannot be subscripted")
|
|
44
|
+
|
|
45
|
+
@override
|
|
46
|
+
def emit_getattr(self, attr: str) -> JSExpr:
|
|
47
|
+
value = self.transpiler.get(attr)
|
|
48
|
+
if value is None:
|
|
49
|
+
raise JSCompilationError(f"Module has no attribute '{attr}'")
|
|
50
|
+
# transpiler always contains JSExpr (wrapping happens in register_module)
|
|
51
|
+
return value
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class PyModule:
|
|
55
|
+
"""Base class for Python module transpilation mappings.
|
|
56
|
+
|
|
57
|
+
Subclasses define static methods and class attributes that map Python module
|
|
58
|
+
functions and constants to their JavaScript equivalents.
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
class PyMath(PyModule):
|
|
62
|
+
# Constants - JSExpr values
|
|
63
|
+
pi = JSMember(JSIdentifier("Math"), "PI")
|
|
64
|
+
|
|
65
|
+
# Functions - return JSExpr
|
|
66
|
+
@staticmethod
|
|
67
|
+
def floor(x: JSExpr) -> JSExpr:
|
|
68
|
+
return JSMemberCall(JSIdentifier("Math"), "floor", [x])
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
PY_MODULES: dict[ModuleType, PyModuleTranspiler] = {}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def register_module(
|
|
76
|
+
module: ModuleType,
|
|
77
|
+
transpilation: type[PyModule] | dict[str, JSExpr | Callable[..., JSExpr]],
|
|
78
|
+
) -> None:
|
|
79
|
+
"""Register a Python module for transpilation.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
module: The Python module to register (e.g., `math`, `pulse.html.tags`)
|
|
83
|
+
transpilation: Either a PyModule subclass or a dict mapping attribute names
|
|
84
|
+
to JSExpr (for constants) or Callable[..., JSExpr] (for functions).
|
|
85
|
+
Callables will be wrapped in JSTransformer during registration.
|
|
86
|
+
"""
|
|
87
|
+
# Convert PyModule class to dict if needed (wraps callables)
|
|
88
|
+
transpiler_dict: PyModuleTranspiler = {}
|
|
89
|
+
|
|
90
|
+
# Get items to iterate over - either from dict or PyModule class
|
|
91
|
+
if isinstance(transpilation, dict):
|
|
92
|
+
items = transpilation.items()
|
|
93
|
+
else:
|
|
94
|
+
# Convert PyModule class to (name, attr) pairs
|
|
95
|
+
items = (
|
|
96
|
+
(attr_name, getattr(transpilation, attr_name, None))
|
|
97
|
+
for attr_name in dir(transpilation)
|
|
98
|
+
if not attr_name.startswith("_")
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Normalize: wrap callables in JSTransformer and register via JSExpr.register
|
|
102
|
+
for attr_name, attr in items:
|
|
103
|
+
if isinstance(attr, JSExpr):
|
|
104
|
+
pass
|
|
105
|
+
elif callable(attr):
|
|
106
|
+
# Wrap callables in JSTransformer so result always contains JSExpr
|
|
107
|
+
attr = JSTransformer(cast(Callable[..., JSExpr], attr))
|
|
108
|
+
else:
|
|
109
|
+
# Skip non-JSExpr, non-callable values
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
transpiler_dict[attr_name] = attr
|
|
113
|
+
# Register the module attribute value for lookup by id
|
|
114
|
+
module_value = getattr(module, attr_name, None)
|
|
115
|
+
if module_value is not None:
|
|
116
|
+
JSExpr.register(module_value, attr)
|
|
117
|
+
|
|
118
|
+
# Store as dict (now normalized to only JSExpr)
|
|
119
|
+
PY_MODULES[module] = transpiler_dict
|