pulse-framework 0.1.46__py3-none-any.whl → 0.1.48__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 (73) hide show
  1. pulse/__init__.py +9 -23
  2. pulse/app.py +6 -25
  3. pulse/cli/processes.py +1 -0
  4. pulse/codegen/codegen.py +43 -88
  5. pulse/codegen/js.py +35 -5
  6. pulse/codegen/templates/route.py +341 -254
  7. pulse/form.py +1 -1
  8. pulse/helpers.py +51 -27
  9. pulse/hooks/core.py +2 -2
  10. pulse/hooks/effects.py +1 -1
  11. pulse/hooks/init.py +2 -1
  12. pulse/hooks/setup.py +1 -1
  13. pulse/hooks/stable.py +2 -2
  14. pulse/hooks/states.py +2 -2
  15. pulse/html/props.py +3 -2
  16. pulse/html/tags.py +135 -0
  17. pulse/html/tags.pyi +4 -0
  18. pulse/js/__init__.py +110 -0
  19. pulse/js/__init__.pyi +95 -0
  20. pulse/js/_types.py +297 -0
  21. pulse/js/array.py +253 -0
  22. pulse/js/console.py +47 -0
  23. pulse/js/date.py +113 -0
  24. pulse/js/document.py +138 -0
  25. pulse/js/error.py +139 -0
  26. pulse/js/json.py +62 -0
  27. pulse/js/map.py +84 -0
  28. pulse/js/math.py +66 -0
  29. pulse/js/navigator.py +76 -0
  30. pulse/js/number.py +54 -0
  31. pulse/js/object.py +173 -0
  32. pulse/js/promise.py +150 -0
  33. pulse/js/regexp.py +54 -0
  34. pulse/js/set.py +109 -0
  35. pulse/js/string.py +35 -0
  36. pulse/js/weakmap.py +50 -0
  37. pulse/js/weakset.py +45 -0
  38. pulse/js/window.py +199 -0
  39. pulse/messages.py +22 -3
  40. pulse/proxy.py +21 -8
  41. pulse/react_component.py +167 -14
  42. pulse/reactive_extensions.py +5 -5
  43. pulse/render_session.py +144 -34
  44. pulse/renderer.py +80 -115
  45. pulse/routing.py +1 -18
  46. pulse/transpiler/__init__.py +131 -0
  47. pulse/transpiler/builtins.py +731 -0
  48. pulse/transpiler/constants.py +110 -0
  49. pulse/transpiler/context.py +26 -0
  50. pulse/transpiler/errors.py +2 -0
  51. pulse/transpiler/function.py +250 -0
  52. pulse/transpiler/ids.py +16 -0
  53. pulse/transpiler/imports.py +409 -0
  54. pulse/transpiler/js_module.py +274 -0
  55. pulse/transpiler/modules/__init__.py +30 -0
  56. pulse/transpiler/modules/asyncio.py +38 -0
  57. pulse/transpiler/modules/json.py +20 -0
  58. pulse/transpiler/modules/math.py +320 -0
  59. pulse/transpiler/modules/re.py +466 -0
  60. pulse/transpiler/modules/tags.py +268 -0
  61. pulse/transpiler/modules/typing.py +59 -0
  62. pulse/transpiler/nodes.py +1216 -0
  63. pulse/transpiler/py_module.py +119 -0
  64. pulse/transpiler/transpiler.py +938 -0
  65. pulse/transpiler/utils.py +4 -0
  66. pulse/vdom.py +112 -6
  67. {pulse_framework-0.1.46.dist-info → pulse_framework-0.1.48.dist-info}/METADATA +1 -1
  68. pulse_framework-0.1.48.dist-info/RECORD +119 -0
  69. pulse/codegen/imports.py +0 -204
  70. pulse/css.py +0 -155
  71. pulse_framework-0.1.46.dist-info/RECORD +0 -80
  72. {pulse_framework-0.1.46.dist-info → pulse_framework-0.1.48.dist-info}/WHEEL +0 -0
  73. {pulse_framework-0.1.46.dist-info → pulse_framework-0.1.48.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,38 @@
1
+ """Python asyncio module transpilation to JavaScript Promise operations.
2
+
3
+ This module provides transpilation from Python's `asyncio` module to JavaScript's `Promise` methods.
4
+ """
5
+
6
+ from pulse.transpiler.nodes import JSArray, JSExpr, JSIdentifier, JSMemberCall
7
+ from pulse.transpiler.py_module import PyModule
8
+
9
+
10
+ class PyAsyncio(PyModule):
11
+ """Provides transpilation for Python asyncio functions to JavaScript Promise methods."""
12
+
13
+ @staticmethod
14
+ def gather(*coros: JSExpr, **kwargs: JSExpr) -> JSExpr:
15
+ """Transpile asyncio.gather to Promise.all or Promise.allSettled.
16
+
17
+ Args:
18
+ *coros: Variable number of coroutine/promise expressions
19
+ **kwargs: Keyword arguments, including return_exceptions
20
+
21
+ Returns:
22
+ JSExpr representing Promise.all([...]) or Promise.allSettled([...])
23
+ """
24
+ # Convert coros to array
25
+ promises = JSArray(list(coros))
26
+
27
+ # Check return_exceptions keyword argument
28
+ return_exceptions = kwargs.get("return_exceptions")
29
+ if return_exceptions is not None:
30
+ # Check if it's a boolean true (JSBoolean(True))
31
+ from pulse.transpiler.nodes import JSBoolean
32
+
33
+ if isinstance(return_exceptions, JSBoolean) and return_exceptions.value:
34
+ # Promise.allSettled returns results with status
35
+ return JSMemberCall(JSIdentifier("Promise"), "allSettled", [promises])
36
+
37
+ # Default: Promise.all fails fast on first rejection
38
+ return JSMemberCall(JSIdentifier("Promise"), "all", [promises])
@@ -0,0 +1,20 @@
1
+ """Python json module transpilation to JavaScript JSON."""
2
+
3
+ from pulse.transpiler.nodes import JSExpr, JSIdentifier, JSMemberCall
4
+ from pulse.transpiler.py_module import PyModule
5
+
6
+
7
+ def JSONCall(name: str, *args: JSExpr) -> JSExpr:
8
+ return JSMemberCall(JSIdentifier("JSON"), name, list(args))
9
+
10
+
11
+ class PyJson(PyModule):
12
+ """Provides transpilation for Python json functions to JavaScript."""
13
+
14
+ @staticmethod
15
+ def dumps(obj: JSExpr) -> JSExpr:
16
+ return JSONCall("stringify", obj)
17
+
18
+ @staticmethod
19
+ def loads(s: JSExpr) -> JSExpr:
20
+ return JSONCall("parse", s)
@@ -0,0 +1,320 @@
1
+ """Python math module transpilation to JavaScript Math.
2
+
3
+ This module provides transpilation from Python's `math` module to JavaScript's `Math` object.
4
+ For direct JavaScript Math bindings, use `pulse.js.math` instead.
5
+ """
6
+
7
+ # pyright: reportUnannotatedClassAttribute=false
8
+
9
+ from pulse.transpiler.constants import jsify
10
+ from pulse.transpiler.nodes import (
11
+ JSBinary,
12
+ JSExpr,
13
+ JSIdentifier,
14
+ JSMember,
15
+ JSMemberCall,
16
+ JSNumber,
17
+ JSUnary,
18
+ )
19
+ from pulse.transpiler.py_module import PyModule
20
+
21
+
22
+ # Helper for generating Math method calls during transpilation
23
+ def MathCall(name: str, *args: int | float | JSExpr) -> JSExpr:
24
+ return JSMemberCall(JSIdentifier("Math"), name, [jsify(a) for a in args])
25
+
26
+
27
+ def MathProp(name: str) -> JSExpr:
28
+ return JSMember(JSIdentifier("Math"), name)
29
+
30
+
31
+ class PyMath(PyModule):
32
+ """Provides transpilation for Python math functions to JavaScript."""
33
+
34
+ # Constants (as class attributes returning JSExpr)
35
+ pi = MathProp("PI")
36
+ e = MathProp("E")
37
+ tau = JSBinary(JSNumber(2), "*", MathProp("PI")) # 2 * PI
38
+ inf = JSIdentifier("Infinity")
39
+ nan = JSIdentifier("NaN")
40
+
41
+ @staticmethod
42
+ def acos(x: int | float | JSExpr) -> JSExpr:
43
+ return MathCall("acos", x)
44
+
45
+ @staticmethod
46
+ def acosh(x: int | float | JSExpr) -> JSExpr:
47
+ return MathCall("acosh", x)
48
+
49
+ @staticmethod
50
+ def asin(x: int | float | JSExpr) -> JSExpr:
51
+ return MathCall("asin", x)
52
+
53
+ @staticmethod
54
+ def asinh(x: int | float | JSExpr) -> JSExpr:
55
+ return MathCall("asinh", x)
56
+
57
+ @staticmethod
58
+ def atan(x: int | float | JSExpr) -> JSExpr:
59
+ return MathCall("atan", x)
60
+
61
+ @staticmethod
62
+ def atan2(y: int | float | JSExpr, x: int | float | JSExpr) -> JSExpr:
63
+ return MathCall("atan2", y, x)
64
+
65
+ @staticmethod
66
+ def atanh(x: int | float | JSExpr) -> JSExpr:
67
+ return MathCall("atanh", x)
68
+
69
+ @staticmethod
70
+ def cbrt(x: int | float | JSExpr) -> JSExpr:
71
+ return MathCall("cbrt", x)
72
+
73
+ @staticmethod
74
+ def ceil(x: int | float | JSExpr) -> JSExpr:
75
+ return MathCall("ceil", x)
76
+
77
+ @staticmethod
78
+ def copysign(x: int | float | JSExpr, y: int | float | JSExpr) -> JSExpr:
79
+ # Math.sign(y) * Math.abs(x)
80
+ return JSBinary(MathCall("sign", y), "*", MathCall("abs", x))
81
+
82
+ @staticmethod
83
+ def cos(x: int | float | JSExpr) -> JSExpr:
84
+ return MathCall("cos", x)
85
+
86
+ @staticmethod
87
+ def cosh(x: int | float | JSExpr) -> JSExpr:
88
+ return MathCall("cosh", x)
89
+
90
+ @staticmethod
91
+ def degrees(x: int | float | JSExpr) -> JSExpr:
92
+ # Convert radians to degrees: x * (180 / π)
93
+ return JSBinary(jsify(x), "*", JSBinary(JSNumber(180), "/", MathProp("PI")))
94
+
95
+ @staticmethod
96
+ def dist(
97
+ p: int | float | JSExpr | list[int | float | JSExpr],
98
+ q: int | float | JSExpr | list[int | float | JSExpr],
99
+ ) -> JSExpr:
100
+ raise NotImplementedError("dist requires array/iterable handling")
101
+
102
+ @staticmethod
103
+ def erf(x: int | float | JSExpr) -> JSExpr:
104
+ raise NotImplementedError("erf requires special function implementation")
105
+
106
+ @staticmethod
107
+ def erfc(x: int | float | JSExpr) -> JSExpr:
108
+ raise NotImplementedError("erfc requires special function implementation")
109
+
110
+ @staticmethod
111
+ def exp(x: int | float | JSExpr) -> JSExpr:
112
+ return MathCall("exp", x)
113
+
114
+ @staticmethod
115
+ def exp2(x: int | float | JSExpr) -> JSExpr:
116
+ # 2 ** x
117
+ return JSBinary(JSNumber(2), "**", jsify(x))
118
+
119
+ @staticmethod
120
+ def expm1(x: int | float | JSExpr) -> JSExpr:
121
+ return MathCall("expm1", x)
122
+
123
+ @staticmethod
124
+ def fabs(x: int | float | JSExpr) -> JSExpr:
125
+ return MathCall("abs", x)
126
+
127
+ @staticmethod
128
+ def factorial(x: int | float | JSExpr) -> JSExpr:
129
+ raise NotImplementedError("factorial requires iterative implementation")
130
+
131
+ @staticmethod
132
+ def floor(x: int | float | JSExpr) -> JSExpr:
133
+ return MathCall("floor", x)
134
+
135
+ @staticmethod
136
+ def fmod(x: int | float | JSExpr, y: int | float | JSExpr) -> JSExpr:
137
+ # JavaScript % operator matches Python fmod for most cases
138
+ return JSBinary(jsify(x), "%", jsify(y))
139
+
140
+ @staticmethod
141
+ def frexp(x: int | float | JSExpr) -> JSExpr:
142
+ raise NotImplementedError("frexp returns tuple, requires special handling")
143
+
144
+ @staticmethod
145
+ def fsum(seq: int | float | JSExpr | list[int | float | JSExpr]) -> JSExpr:
146
+ raise NotImplementedError("fsum requires iterable handling")
147
+
148
+ @staticmethod
149
+ def gamma(x: int | float | JSExpr) -> JSExpr:
150
+ raise NotImplementedError("gamma requires special function implementation")
151
+
152
+ @staticmethod
153
+ def gcd(*integers: int | float | JSExpr) -> JSExpr:
154
+ raise NotImplementedError("gcd requires iterative implementation")
155
+
156
+ @staticmethod
157
+ def hypot(*coordinates: int | float | JSExpr) -> JSExpr:
158
+ return MathCall("hypot", *coordinates)
159
+
160
+ @staticmethod
161
+ def isclose(
162
+ a: int | float | JSExpr,
163
+ b: int | float | JSExpr,
164
+ *,
165
+ rel_tol: int | float | JSExpr = 1e-09,
166
+ abs_tol: int | float | JSExpr = 0.0,
167
+ ) -> JSExpr:
168
+ # abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
169
+ abs_diff = MathCall("abs", JSBinary(jsify(a), "-", jsify(b)))
170
+ max_abs = JSMemberCall(
171
+ JSIdentifier("Math"),
172
+ "max",
173
+ [MathCall("abs", a), MathCall("abs", b)],
174
+ )
175
+ rel_bound = JSBinary(jsify(rel_tol), "*", max_abs)
176
+ max_bound = JSMemberCall(
177
+ JSIdentifier("Math"), "max", [rel_bound, jsify(abs_tol)]
178
+ )
179
+ return JSBinary(abs_diff, "<=", max_bound)
180
+
181
+ @staticmethod
182
+ def isfinite(x: int | float | JSExpr) -> JSExpr:
183
+ return JSMemberCall(JSIdentifier("Number"), "isFinite", [jsify(x)])
184
+
185
+ @staticmethod
186
+ def isinf(x: int | float | JSExpr) -> JSExpr:
187
+ is_finite = JSMemberCall(JSIdentifier("Number"), "isFinite", [jsify(x)])
188
+ is_nan = JSMemberCall(JSIdentifier("Number"), "isNaN", [jsify(x)])
189
+ return JSBinary(JSUnary("!", is_finite), "&&", JSUnary("!", is_nan))
190
+
191
+ @staticmethod
192
+ def isnan(x: int | float | JSExpr) -> JSExpr:
193
+ return JSMemberCall(JSIdentifier("Number"), "isNaN", [jsify(x)])
194
+
195
+ @staticmethod
196
+ def isqrt(n: int | float | JSExpr) -> JSExpr:
197
+ return MathCall("floor", MathCall("sqrt", n))
198
+
199
+ @staticmethod
200
+ def lcm(*integers: int | float | JSExpr) -> JSExpr:
201
+ raise NotImplementedError("lcm requires iterative implementation")
202
+
203
+ @staticmethod
204
+ def ldexp(x: int | float | JSExpr, i: int | float | JSExpr) -> JSExpr:
205
+ # x * (2 ** i)
206
+ return JSBinary(jsify(x), "*", JSBinary(JSNumber(2), "**", jsify(i)))
207
+
208
+ @staticmethod
209
+ def lgamma(x: int | float | JSExpr) -> JSExpr:
210
+ raise NotImplementedError("lgamma requires special function implementation")
211
+
212
+ @staticmethod
213
+ def log(
214
+ value: int | float | JSExpr,
215
+ base: int | float | JSExpr | None = None,
216
+ ) -> JSExpr:
217
+ if base is None:
218
+ return MathCall("log", value)
219
+ return JSBinary(MathCall("log", value), "/", MathCall("log", base))
220
+
221
+ @staticmethod
222
+ def log10(x: int | float | JSExpr) -> JSExpr:
223
+ return MathCall("log10", x)
224
+
225
+ @staticmethod
226
+ def log1p(x: int | float | JSExpr) -> JSExpr:
227
+ return MathCall("log1p", x)
228
+
229
+ @staticmethod
230
+ def log2(x: int | float | JSExpr) -> JSExpr:
231
+ return MathCall("log2", x)
232
+
233
+ @staticmethod
234
+ def modf(x: int | float | JSExpr) -> JSExpr:
235
+ raise NotImplementedError("modf returns tuple, requires special handling")
236
+
237
+ @staticmethod
238
+ def nextafter(
239
+ x: int | float | JSExpr,
240
+ y: int | float | JSExpr,
241
+ *,
242
+ steps: int | float | JSExpr | None = None,
243
+ ) -> JSExpr:
244
+ raise NotImplementedError("nextafter requires special implementation")
245
+
246
+ @staticmethod
247
+ def perm(n: int | float | JSExpr, k: int | float | JSExpr | None = None) -> JSExpr:
248
+ raise NotImplementedError("perm requires factorial implementation")
249
+
250
+ @staticmethod
251
+ def pow(x: int | float | JSExpr, y: int | float | JSExpr) -> JSExpr:
252
+ return MathCall("pow", x, y)
253
+
254
+ @staticmethod
255
+ def prod(
256
+ iterable: int | float | JSExpr | list[int | float | JSExpr],
257
+ *,
258
+ start: int | float | JSExpr = 1,
259
+ ) -> JSExpr:
260
+ raise NotImplementedError("prod requires iterable handling")
261
+
262
+ @staticmethod
263
+ def radians(x: int | float | JSExpr) -> JSExpr:
264
+ # Convert degrees to radians: x * (π / 180)
265
+ return JSBinary(jsify(x), "*", JSBinary(MathProp("PI"), "/", JSNumber(180)))
266
+
267
+ @staticmethod
268
+ def remainder(x: int | float | JSExpr, y: int | float | JSExpr) -> JSExpr:
269
+ # x - n * y where n is the nearest integer to x/y
270
+ n = MathCall("round", JSBinary(jsify(x), "/", jsify(y)))
271
+ return JSBinary(jsify(x), "-", JSBinary(n, "*", jsify(y)))
272
+
273
+ @staticmethod
274
+ def sin(x: int | float | JSExpr) -> JSExpr:
275
+ return MathCall("sin", x)
276
+
277
+ @staticmethod
278
+ def sinh(x: int | float | JSExpr) -> JSExpr:
279
+ return MathCall("sinh", x)
280
+
281
+ @staticmethod
282
+ def sqrt(x: int | float | JSExpr) -> JSExpr:
283
+ return MathCall("sqrt", x)
284
+
285
+ @staticmethod
286
+ def sumprod(
287
+ p: int | float | JSExpr | list[int | float | JSExpr],
288
+ q: int | float | JSExpr | list[int | float | JSExpr],
289
+ ) -> JSExpr:
290
+ raise NotImplementedError("sumprod requires iterable handling")
291
+
292
+ @staticmethod
293
+ def tan(x: int | float | JSExpr) -> JSExpr:
294
+ return MathCall("tan", x)
295
+
296
+ @staticmethod
297
+ def tanh(x: int | float | JSExpr) -> JSExpr:
298
+ return MathCall("tanh", x)
299
+
300
+ @staticmethod
301
+ def trunc(x: int | float | JSExpr) -> JSExpr:
302
+ return MathCall("trunc", x)
303
+
304
+ @staticmethod
305
+ def ulp(x: int | float | JSExpr) -> JSExpr:
306
+ raise NotImplementedError("ulp requires special implementation")
307
+
308
+ @staticmethod
309
+ def fma(
310
+ x: int | float | JSExpr,
311
+ y: int | float | JSExpr,
312
+ z: int | float | JSExpr,
313
+ ) -> JSExpr:
314
+ # Fused multiply-add: (x * y) + z (with single rounding)
315
+ # JavaScript doesn't have native fma, so we just do the operation
316
+ return JSBinary(JSBinary(jsify(x), "*", jsify(y)), "+", jsify(z))
317
+
318
+ @staticmethod
319
+ def comb(n: int | float | JSExpr, k: int | float | JSExpr) -> JSExpr:
320
+ raise NotImplementedError("comb requires factorial implementation")