pulse-framework 0.1.50__py3-none-any.whl → 0.1.52__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 (85) hide show
  1. pulse/__init__.py +542 -562
  2. pulse/_examples.py +29 -0
  3. pulse/app.py +0 -14
  4. pulse/cli/cmd.py +96 -80
  5. pulse/cli/dependencies.py +10 -41
  6. pulse/cli/folder_lock.py +3 -3
  7. pulse/cli/helpers.py +40 -67
  8. pulse/cli/logging.py +102 -0
  9. pulse/cli/packages.py +16 -0
  10. pulse/cli/processes.py +40 -23
  11. pulse/codegen/codegen.py +70 -35
  12. pulse/codegen/js.py +2 -4
  13. pulse/codegen/templates/route.py +94 -146
  14. pulse/component.py +115 -0
  15. pulse/components/for_.py +1 -1
  16. pulse/components/if_.py +1 -1
  17. pulse/components/react_router.py +16 -22
  18. pulse/{html → dom}/events.py +1 -1
  19. pulse/{html → dom}/props.py +6 -6
  20. pulse/{html → dom}/tags.py +11 -11
  21. pulse/dom/tags.pyi +480 -0
  22. pulse/form.py +7 -6
  23. pulse/hooks/init.py +1 -13
  24. pulse/js/__init__.py +37 -41
  25. pulse/js/__init__.pyi +22 -2
  26. pulse/js/_types.py +5 -3
  27. pulse/js/array.py +121 -38
  28. pulse/js/console.py +9 -9
  29. pulse/js/date.py +22 -19
  30. pulse/js/document.py +8 -4
  31. pulse/js/error.py +12 -14
  32. pulse/js/json.py +4 -3
  33. pulse/js/map.py +17 -7
  34. pulse/js/math.py +2 -2
  35. pulse/js/navigator.py +4 -4
  36. pulse/js/number.py +8 -8
  37. pulse/js/object.py +9 -13
  38. pulse/js/promise.py +25 -9
  39. pulse/js/regexp.py +6 -6
  40. pulse/js/set.py +20 -8
  41. pulse/js/string.py +7 -7
  42. pulse/js/weakmap.py +6 -6
  43. pulse/js/weakset.py +6 -6
  44. pulse/js/window.py +17 -14
  45. pulse/messages.py +1 -4
  46. pulse/react_component.py +3 -999
  47. pulse/render_session.py +74 -66
  48. pulse/renderer.py +311 -238
  49. pulse/routing.py +1 -10
  50. pulse/serializer.py +11 -1
  51. pulse/transpiler/__init__.py +84 -114
  52. pulse/transpiler/builtins.py +661 -343
  53. pulse/transpiler/errors.py +78 -2
  54. pulse/transpiler/function.py +463 -133
  55. pulse/transpiler/id.py +18 -0
  56. pulse/transpiler/imports.py +230 -325
  57. pulse/transpiler/js_module.py +218 -209
  58. pulse/transpiler/modules/__init__.py +16 -13
  59. pulse/transpiler/modules/asyncio.py +45 -26
  60. pulse/transpiler/modules/json.py +12 -8
  61. pulse/transpiler/modules/math.py +161 -216
  62. pulse/transpiler/modules/pulse/__init__.py +5 -0
  63. pulse/transpiler/modules/pulse/tags.py +231 -0
  64. pulse/transpiler/modules/typing.py +33 -28
  65. pulse/transpiler/nodes.py +1607 -923
  66. pulse/transpiler/py_module.py +118 -95
  67. pulse/transpiler/react_component.py +51 -0
  68. pulse/transpiler/transpiler.py +593 -437
  69. pulse/transpiler/vdom.py +255 -0
  70. {pulse_framework-0.1.50.dist-info → pulse_framework-0.1.52.dist-info}/METADATA +1 -1
  71. pulse_framework-0.1.52.dist-info/RECORD +120 -0
  72. pulse/html/tags.pyi +0 -470
  73. pulse/transpiler/constants.py +0 -110
  74. pulse/transpiler/context.py +0 -26
  75. pulse/transpiler/ids.py +0 -16
  76. pulse/transpiler/modules/re.py +0 -466
  77. pulse/transpiler/modules/tags.py +0 -268
  78. pulse/transpiler/utils.py +0 -4
  79. pulse/vdom.py +0 -667
  80. pulse_framework-0.1.50.dist-info/RECORD +0 -119
  81. /pulse/{html → dom}/__init__.py +0 -0
  82. /pulse/{html → dom}/elements.py +0 -0
  83. /pulse/{html → dom}/svg.py +0 -0
  84. {pulse_framework-0.1.50.dist-info → pulse_framework-0.1.52.dist-info}/WHEEL +0 -0
  85. {pulse_framework-0.1.50.dist-info → pulse_framework-0.1.52.dist-info}/entry_points.txt +0 -0
pulse/dom/tags.pyi ADDED
@@ -0,0 +1,480 @@
1
+ from typing import Any, Protocol, Unpack
2
+
3
+ from pulse.dom.elements import GenericHTMLElement
4
+ from pulse.dom.props import (
5
+ HTMLAnchorProps,
6
+ HTMLAreaProps,
7
+ HTMLAudioProps,
8
+ HTMLBaseProps,
9
+ HTMLBlockquoteProps,
10
+ HTMLButtonProps,
11
+ HTMLCanvasProps,
12
+ HTMLColgroupProps,
13
+ HTMLColProps,
14
+ HTMLDataProps,
15
+ HTMLDelProps,
16
+ HTMLDetailsProps,
17
+ HTMLDialogProps,
18
+ HTMLEmbedProps,
19
+ HTMLFieldsetProps,
20
+ HTMLFormProps,
21
+ HTMLHtmlProps,
22
+ HTMLIframeProps,
23
+ HTMLImgProps,
24
+ HTMLInputProps,
25
+ HTMLInsProps,
26
+ HTMLLabelProps,
27
+ HTMLLinkProps,
28
+ HTMLLiProps,
29
+ HTMLMapProps,
30
+ HTMLMenuProps,
31
+ HTMLMetaProps,
32
+ HTMLMeterProps,
33
+ HTMLObjectProps,
34
+ HTMLOlProps,
35
+ HTMLOptgroupProps,
36
+ HTMLOptionProps,
37
+ HTMLOutputProps,
38
+ HTMLParamProps,
39
+ HTMLProgressProps,
40
+ HTMLProps,
41
+ HTMLQuoteProps,
42
+ HTMLScriptProps,
43
+ HTMLSelectProps,
44
+ HTMLSourceProps,
45
+ HTMLStyleProps,
46
+ HTMLSVGProps,
47
+ HTMLTableProps,
48
+ HTMLTdProps,
49
+ HTMLTextareaProps,
50
+ HTMLThProps,
51
+ HTMLTimeProps,
52
+ HTMLTrackProps,
53
+ HTMLVideoProps,
54
+ )
55
+ from pulse.transpiler.nodes import Element, Node
56
+
57
+ class Tag(Protocol):
58
+ def __call__(self, *children: Node, **props: Any) -> Element: ...
59
+
60
+ def define_tag(
61
+ name: str,
62
+ default_props: dict[str, Any] | None = None,
63
+ ) -> Tag: ...
64
+ def define_self_closing_tag(
65
+ name: str,
66
+ default_props: dict[str, Any] | None = None,
67
+ ) -> Tag: ...
68
+
69
+ # --- Self-closing tags ----
70
+ def area(*, key: str | None = None, **props: Unpack[HTMLAreaProps]) -> Element: ...
71
+ def base(*, key: str | None = None, **props: Unpack[HTMLBaseProps]) -> Element: ...
72
+ def br(*, key: str | None = None, **props: Unpack[HTMLProps]) -> Element: ...
73
+ def col(*, key: str | None = None, **props: Unpack[HTMLColProps]) -> Element: ...
74
+ def embed(*, key: str | None = None, **props: Unpack[HTMLEmbedProps]) -> Element: ...
75
+ def hr(*, key: str | None = None, **props: Unpack[HTMLProps]) -> Element: ...
76
+ def img(*, key: str | None = None, **props: Unpack[HTMLImgProps]) -> Element: ...
77
+ def input(*, key: str | None = None, **props: Unpack[HTMLInputProps]) -> Element: ...
78
+ def link(*, key: str | None = None, **props: Unpack[HTMLLinkProps]) -> Element: ...
79
+ def meta(*, key: str | None = None, **props: Unpack[HTMLMetaProps]) -> Element: ...
80
+ def param(*, key: str | None = None, **props: Unpack[HTMLParamProps]) -> Element: ...
81
+ def source(*, key: str | None = None, **props: Unpack[HTMLSourceProps]) -> Element: ...
82
+ def track(*, key: str | None = None, **props: Unpack[HTMLTrackProps]) -> Element: ...
83
+ def wbr(*, key: str | None = None, **props: Unpack[HTMLProps]) -> Element: ...
84
+
85
+ # --- Regular tags ---
86
+
87
+ def a(
88
+ *children: Node, key: str | None = None, **props: Unpack[HTMLAnchorProps]
89
+ ) -> Element: ...
90
+ def abbr(
91
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
92
+ ) -> Element: ...
93
+ def address(
94
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
95
+ ) -> Element: ...
96
+ def article(
97
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
98
+ ) -> Element: ...
99
+ def aside(
100
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
101
+ ) -> Element: ...
102
+ def audio(
103
+ *children: Node, key: str | None = None, **props: Unpack[HTMLAudioProps]
104
+ ) -> Element: ...
105
+ def b(
106
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
107
+ ) -> Element: ...
108
+ def bdi(
109
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
110
+ ) -> Element: ...
111
+ def bdo(
112
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
113
+ ) -> Element: ...
114
+ def blockquote(
115
+ *children: Node,
116
+ key: str | None = None,
117
+ **props: Unpack[HTMLBlockquoteProps],
118
+ ) -> Element: ...
119
+ def body(
120
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
121
+ ) -> Element: ...
122
+ def button(
123
+ *children: Node, key: str | None = None, **props: Unpack[HTMLButtonProps]
124
+ ) -> Element: ...
125
+ def canvas(
126
+ *children: Node, key: str | None = None, **props: Unpack[HTMLCanvasProps]
127
+ ) -> Element: ...
128
+ def caption(
129
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
130
+ ) -> Element: ...
131
+ def cite(
132
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
133
+ ) -> Element: ...
134
+ def code(
135
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
136
+ ) -> Element: ...
137
+ def colgroup(
138
+ *children: Node,
139
+ key: str | None = None,
140
+ **props: Unpack[HTMLColgroupProps],
141
+ ) -> Element: ...
142
+ def data(
143
+ *children: Node, key: str | None = None, **props: Unpack[HTMLDataProps]
144
+ ) -> Element: ...
145
+ def datalist(
146
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
147
+ ) -> Element: ...
148
+ def dd(
149
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
150
+ ) -> Element: ...
151
+ def del_(
152
+ *children: Node, key: str | None = None, **props: Unpack[HTMLDelProps]
153
+ ) -> Element: ...
154
+ def details(
155
+ *children: Node,
156
+ key: str | None = None,
157
+ **props: Unpack[HTMLDetailsProps],
158
+ ) -> Element: ...
159
+ def dfn(
160
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
161
+ ) -> Element: ...
162
+ def dialog(
163
+ *children: Node, key: str | None = None, **props: Unpack[HTMLDialogProps]
164
+ ) -> Element: ...
165
+ def div(
166
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
167
+ ) -> Element: ...
168
+ def dl(
169
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
170
+ ) -> Element: ...
171
+ def dt(
172
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
173
+ ) -> Element: ...
174
+ def em(
175
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
176
+ ) -> Element: ...
177
+ def fieldset(
178
+ *children: Node,
179
+ key: str | None = None,
180
+ **props: Unpack[HTMLFieldsetProps],
181
+ ) -> Element: ...
182
+ def figcaption(
183
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
184
+ ) -> Element: ...
185
+ def figure(
186
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
187
+ ) -> Element: ...
188
+ def footer(
189
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
190
+ ) -> Element: ...
191
+ def form(
192
+ *children: Node, key: str | None = None, **props: Unpack[HTMLFormProps]
193
+ ) -> Element: ...
194
+ def h1(
195
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
196
+ ) -> Element: ...
197
+ def h2(
198
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
199
+ ) -> Element: ...
200
+ def h3(
201
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
202
+ ) -> Element: ...
203
+ def h4(
204
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
205
+ ) -> Element: ...
206
+ def h5(
207
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
208
+ ) -> Element: ...
209
+ def h6(
210
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
211
+ ) -> Element: ...
212
+ def head(
213
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
214
+ ) -> Element: ...
215
+ def header(
216
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
217
+ ) -> Element: ...
218
+ def hgroup(
219
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
220
+ ) -> Element: ...
221
+ def html(
222
+ *children: Node, key: str | None = None, **props: Unpack[HTMLHtmlProps]
223
+ ) -> Element: ...
224
+ def i(
225
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
226
+ ) -> Element: ...
227
+ def iframe(
228
+ *children: Node, key: str | None = None, **props: Unpack[HTMLIframeProps]
229
+ ) -> Element: ...
230
+ def ins(
231
+ *children: Node, key: str | None = None, **props: Unpack[HTMLInsProps]
232
+ ) -> Element: ...
233
+ def kbd(
234
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
235
+ ) -> Element: ...
236
+ def label(
237
+ *children: Node, key: str | None = None, **props: Unpack[HTMLLabelProps]
238
+ ) -> Element: ...
239
+ def legend(
240
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
241
+ ) -> Element: ...
242
+ def li(
243
+ *children: Node, key: str | None = None, **props: Unpack[HTMLLiProps]
244
+ ) -> Element: ...
245
+ def main(
246
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
247
+ ) -> Element: ...
248
+ def map_(
249
+ *children: Node, key: str | None = None, **props: Unpack[HTMLMapProps]
250
+ ) -> Element: ...
251
+ def mark(
252
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
253
+ ) -> Element: ...
254
+ def menu(
255
+ *children: Node, key: str | None = None, **props: Unpack[HTMLMenuProps]
256
+ ) -> Element: ...
257
+ def meter(
258
+ *children: Node, key: str | None = None, **props: Unpack[HTMLMeterProps]
259
+ ) -> Element: ...
260
+ def nav(
261
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
262
+ ) -> Element: ...
263
+ def noscript(
264
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
265
+ ) -> Element: ...
266
+ def object_(
267
+ *children: Node, key: str | None = None, **props: Unpack[HTMLObjectProps]
268
+ ) -> Element: ...
269
+ def ol(
270
+ *children: Node, key: str | None = None, **props: Unpack[HTMLOlProps]
271
+ ) -> Element: ...
272
+ def optgroup(
273
+ *children: Node,
274
+ key: str | None = None,
275
+ **props: Unpack[HTMLOptgroupProps],
276
+ ) -> Element: ...
277
+ def option(
278
+ *children: Node, key: str | None = None, **props: Unpack[HTMLOptionProps]
279
+ ) -> Element: ...
280
+ def output(
281
+ *children: Node, key: str | None = None, **props: Unpack[HTMLOutputProps]
282
+ ) -> Element: ...
283
+ def p(
284
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
285
+ ) -> Element: ...
286
+ def picture(
287
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
288
+ ) -> Element: ...
289
+ def pre(
290
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
291
+ ) -> Element: ...
292
+ def progress(
293
+ *children: Node,
294
+ key: str | None = None,
295
+ **props: Unpack[HTMLProgressProps],
296
+ ) -> Element: ...
297
+ def q(
298
+ *children: Node, key: str | None = None, **props: Unpack[HTMLQuoteProps]
299
+ ) -> Element: ...
300
+ def rp(
301
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
302
+ ) -> Element: ...
303
+ def rt(
304
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
305
+ ) -> Element: ...
306
+ def ruby(
307
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
308
+ ) -> Element: ...
309
+ def s(
310
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
311
+ ) -> Element: ...
312
+ def samp(
313
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
314
+ ) -> Element: ...
315
+ def script(
316
+ *children: Node, key: str | None = None, **props: Unpack[HTMLScriptProps]
317
+ ) -> Element: ...
318
+ def section(
319
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
320
+ ) -> Element: ...
321
+ def select(
322
+ *children: Node, key: str | None = None, **props: Unpack[HTMLSelectProps]
323
+ ) -> Element: ...
324
+ def small(
325
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
326
+ ) -> Element: ...
327
+ def span(
328
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
329
+ ) -> Element: ...
330
+ def strong(
331
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
332
+ ) -> Element: ...
333
+ def style(
334
+ *children: Node, key: str | None = None, **props: Unpack[HTMLStyleProps]
335
+ ) -> Element: ...
336
+ def sub(
337
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
338
+ ) -> Element: ...
339
+ def summary(
340
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
341
+ ) -> Element: ...
342
+ def sup(
343
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
344
+ ) -> Element: ...
345
+ def table(
346
+ *children: Node, key: str | None = None, **props: Unpack[HTMLTableProps]
347
+ ) -> Element: ...
348
+ def tbody(
349
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
350
+ ) -> Element: ...
351
+ def td(
352
+ *children: Node, key: str | None = None, **props: Unpack[HTMLTdProps]
353
+ ) -> Element: ...
354
+ def template(
355
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
356
+ ) -> Element: ...
357
+ def textarea(
358
+ *children: Node,
359
+ key: str | None = None,
360
+ **props: Unpack[HTMLTextareaProps],
361
+ ) -> Element: ...
362
+ def tfoot(
363
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
364
+ ) -> Element: ...
365
+ def th(
366
+ *children: Node, key: str | None = None, **props: Unpack[HTMLThProps]
367
+ ) -> Element: ...
368
+ def thead(
369
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
370
+ ) -> Element: ...
371
+ def time(
372
+ *children: Node, key: str | None = None, **props: Unpack[HTMLTimeProps]
373
+ ) -> Element: ...
374
+ def title(
375
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
376
+ ) -> Element: ...
377
+ def tr(
378
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
379
+ ) -> Element: ...
380
+ def u(
381
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
382
+ ) -> Element: ...
383
+ def ul(
384
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
385
+ ) -> Element: ...
386
+ def var(
387
+ *children: Node, key: str | None = None, **props: Unpack[HTMLProps]
388
+ ) -> Element: ...
389
+ def video(
390
+ *children: Node, key: str | None = None, **props: Unpack[HTMLVideoProps]
391
+ ) -> Element: ...
392
+
393
+ # -- React Fragment ---
394
+ def fragment(*children: Node, key: str | None = None) -> Element: ...
395
+
396
+ # -- SVG --
397
+ def svg(
398
+ *children: Node,
399
+ key: str | None = None,
400
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
401
+ ) -> Element: ...
402
+ def circle(
403
+ *children: Node,
404
+ key: str | None = None,
405
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
406
+ ) -> Element: ...
407
+ def ellipse(
408
+ *children: Node,
409
+ key: str | None = None,
410
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
411
+ ) -> Element: ...
412
+ def g(
413
+ *children: Node,
414
+ key: str | None = None,
415
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
416
+ ) -> Element: ...
417
+ def line(
418
+ *children: Node,
419
+ key: str | None = None,
420
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
421
+ ) -> Element: ...
422
+ def path(
423
+ *children: Node,
424
+ key: str | None = None,
425
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
426
+ ) -> Element: ...
427
+ def polygon(
428
+ *children: Node,
429
+ key: str | None = None,
430
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
431
+ ) -> Element: ...
432
+ def polyline(
433
+ *children: Node,
434
+ key: str | None = None,
435
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
436
+ ) -> Element: ...
437
+ def rect(
438
+ *children: Node,
439
+ key: str | None = None,
440
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
441
+ ) -> Element: ...
442
+ def text(
443
+ *children: Node,
444
+ key: str | None = None,
445
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
446
+ ) -> Element: ...
447
+ def tspan(
448
+ *children: Node,
449
+ key: str | None = None,
450
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
451
+ ) -> Element: ...
452
+ def defs(
453
+ *children: Node,
454
+ key: str | None = None,
455
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
456
+ ) -> Element: ...
457
+ def clipPath(
458
+ *children: Node,
459
+ key: str | None = None,
460
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
461
+ ) -> Element: ...
462
+ def mask(
463
+ *children: Node,
464
+ key: str | None = None,
465
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
466
+ ) -> Element: ...
467
+ def pattern(
468
+ *children: Node,
469
+ key: str | None = None,
470
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
471
+ ) -> Element: ...
472
+ def use(
473
+ *children: Node,
474
+ key: str | None = None,
475
+ **props: Unpack[HTMLSVGProps[GenericHTMLElement]],
476
+ ) -> Element: ...
477
+
478
+ # Lists exported for JS transpiler
479
+ TAGS: list[tuple[str, dict[str, Any] | None]]
480
+ SELF_CLOSING_TAGS: list[tuple[str, dict[str, Any] | None]]
pulse/form.py CHANGED
@@ -15,16 +15,17 @@ from starlette.datastructures import FormData as StarletteFormData
15
15
  from starlette.datastructures import UploadFile
16
16
 
17
17
  from pulse.context import PulseContext
18
+ from pulse.dom.props import HTMLFormProps
18
19
  from pulse.helpers import Disposable, call_flexible, maybe_await
19
20
  from pulse.hooks.core import HOOK_CONTEXT, HookMetadata, HookState, hooks
20
21
  from pulse.hooks.runtime import server_address
21
22
  from pulse.hooks.stable import stable
22
- from pulse.html.props import HTMLFormProps
23
23
  from pulse.react_component import react_component
24
24
  from pulse.reactive import Signal
25
25
  from pulse.serializer import deserialize
26
+ from pulse.transpiler.imports import Import
27
+ from pulse.transpiler.nodes import Node
26
28
  from pulse.types.event_handler import EventHandler1
27
- from pulse.vdom import Child
28
29
 
29
30
  if TYPE_CHECKING:
30
31
  from pulse.render_session import RenderSession
@@ -45,9 +46,9 @@ FormValue = str | UploadFile
45
46
  FormData = dict[str, FormValue | list[FormValue]]
46
47
 
47
48
 
48
- @react_component("PulseForm", "pulse-ui-client")
49
+ @react_component(Import("PulseForm", "pulse-ui-client"))
49
50
  def client_form_component(
50
- *children: Child,
51
+ *children: Node,
51
52
  key: str | None = None,
52
53
  **props: Unpack[HTMLFormProps],
53
54
  ): ...
@@ -169,7 +170,7 @@ class PulseFormProps(HTMLFormProps, total=False):
169
170
 
170
171
 
171
172
  def Form(
172
- *children: Child,
173
+ *children: Node,
173
174
  key: str,
174
175
  onSubmit: EventHandler1[FormData] | None = None,
175
176
  **props: Unpack[PulseFormProps], # pyright: ignore[reportGeneralTypeIssues]
@@ -259,7 +260,7 @@ class ManualForm(Disposable):
259
260
 
260
261
  def __call__(
261
262
  self,
262
- *children: Child,
263
+ *children: Node,
263
264
  key: str | None = None,
264
265
  **props: Unpack[PulseFormProps],
265
266
  ):
pulse/hooks/init.py CHANGED
@@ -311,7 +311,7 @@ def _collect_assigned_names(body: list[ast.stmt]) -> list[str]:
311
311
  def rewrite_init_blocks(func: Callable[..., Any]) -> Callable[..., Any]:
312
312
  """Rewrite `with ps.init()` blocks in the provided function, if present."""
313
313
 
314
- source = _get_source(func) # raises immediately if missing
314
+ source = textwrap.dedent(getsourcecode(func)) # raises immediately if missing
315
315
 
316
316
  if "init" not in source: # quick prefilter, allow alias detection later
317
317
  return func
@@ -418,18 +418,6 @@ class _InitCallChecker:
418
418
  return False
419
419
 
420
420
 
421
- def _get_source(func: Callable[..., Any]) -> str:
422
- try:
423
- return textwrap.dedent(getsourcecode(func))
424
- except OSError as exc:
425
- src = getattr(func, "__source__", None)
426
- if src is None:
427
- raise RuntimeError(
428
- f"ps.init rewrite failed: unable to read source ({exc})"
429
- ) from exc
430
- return textwrap.dedent(src)
431
-
432
-
433
421
  def _resolve_init_bindings(func: Callable[..., Any]) -> tuple[set[str], set[str]]:
434
422
  """Find names/modules that resolve to pulse.init in the function scope."""
435
423
 
pulse/js/__init__.py CHANGED
@@ -1,51 +1,40 @@
1
- """JavaScript module bindings for use in @javascript decorated functions.
1
+ """JavaScript module bindings for use in @javascript decorated functions (transpiler).
2
2
 
3
3
  Usage:
4
- # For builtins (no import needed in JS):
5
- import pulse.js.math as Math
6
- Math.PI # -> Math.PI
7
-
8
- from pulse.js.math import floor
9
- floor(x) # -> Math.floor(x)
10
-
11
- # Direct import of builtins from pulse.js:
12
- from pulse.js import Set, Number, Array, Math, Date, Promise
13
- Set([1, 2, 3]) # -> new Set([1, 2, 3])
14
- Number.isFinite(42) # -> Number.isFinite(42)
4
+ # Import JS classes (for constructors and static methods):
5
+ from pulse.js import Set, Number, Array, Date, Promise, Map, Error
6
+ Set([1, 2, 3]) # -> new Set([1, 2, 3])
7
+ Number.isFinite(42) # -> Number.isFinite(42)
8
+ Array.isArray(x) # -> Array.isArray(x)
9
+
10
+ # Import JS namespace objects (function-only modules):
11
+ from pulse.js import Math, JSON, console, window, document, navigator
12
+ Math.floor(3.7) # -> Math.floor(3.7)
13
+ JSON.stringify(obj) # -> JSON.stringify(obj)
14
+ console.log("hi") # -> console.log("hi")
15
+
16
+ # Alternative: import namespace modules for namespace access:
17
+ import pulse.js.json as JSON
18
+ JSON.stringify(obj) # -> JSON.stringify(obj)
15
19
 
16
20
  # Statement functions:
17
21
  from pulse.js import throw
18
22
  throw(Error("message")) # -> throw Error("message");
19
23
 
20
- # For external modules:
21
- from pulse.js.lodash import chunk
22
- chunk(arr, 2) # -> import { chunk } from "lodash"; chunk(arr, 2)
23
-
24
- import pulse.js.lodash as _
25
- _.debounce(fn, 100) # -> import _ from "lodash"; _.debounce(fn, 100)
24
+ # Object literals (plain JS objects instead of Map):
25
+ from pulse.js import obj
26
+ obj(a=1, b=2) # -> { a: 1, b: 2 }
26
27
  """
27
28
 
28
29
  import importlib as _importlib
29
30
  from typing import Any as _Any
30
31
  from typing import NoReturn as _NoReturn
31
32
 
32
- from pulse.transpiler.nodes import (
33
- JSIdentifier as _JSIdentifier,
34
- )
35
- from pulse.transpiler.nodes import (
36
- JSStmtExpr as _JSStmtExpr,
37
- )
38
- from pulse.transpiler.nodes import (
39
- JSThrow as _JSThrow,
40
- )
41
- from pulse.transpiler.nodes import (
42
- JSUndefined as _JSUndefined,
43
- )
44
- from pulse.transpiler.nodes import (
45
- js_transformer as _js_transformer,
46
- )
47
-
48
- # Namespace modules that resolve to JSIdentifier
33
+ from pulse.transpiler.builtins import obj as obj
34
+ from pulse.transpiler.nodes import UNDEFINED as _UNDEFINED
35
+ from pulse.transpiler.nodes import Identifier as _Identifier
36
+
37
+ # Namespace modules that resolve to Identifier
49
38
  _MODULE_EXPORTS_IDENTIFIER: dict[str, str] = {
50
39
  "JSON": "pulse.js.json",
51
40
  "Math": "pulse.js.math",
@@ -73,14 +62,21 @@ _MODULE_EXPORTS_ATTRIBUTE: dict[str, str] = {
73
62
 
74
63
 
75
64
  # Statement-like functions (not classes/objects, but callable transformers)
76
- @_js_transformer("throw")
77
- def throw(x: _Any) -> _NoReturn:
78
- # x is typed as _Any for users, but at transpile time it's JSExpr
79
- return _JSStmtExpr(_JSThrow(x), name="throw") # pyright: ignore[reportGeneralTypeIssues]
65
+ # Note: throw needs special handling in the transpiler to convert from expression to statement
66
+ class _ThrowExpr:
67
+ """Wrapper for throw that can be detected and converted to a statement."""
68
+
69
+ def __call__(self, x: _Any) -> _NoReturn:
70
+ # This will be replaced during transpilation
71
+ # The transpiler should detect this and emit as a Throw statement
72
+ raise RuntimeError("throw() can only be used in @javascript functions")
73
+
74
+
75
+ throw = _ThrowExpr()
80
76
 
81
77
 
82
78
  # JS primitive values
83
- undefined = _JSUndefined()
79
+ undefined = _UNDEFINED
84
80
 
85
81
 
86
82
  # Cache for exported values
@@ -99,7 +95,7 @@ def __getattr__(name: str) -> _Any:
99
95
  # Check which dict contains the name
100
96
  if name in _MODULE_EXPORTS_IDENTIFIER:
101
97
  module = _importlib.import_module(_MODULE_EXPORTS_IDENTIFIER[name])
102
- export = _JSIdentifier(name)
98
+ export = _Identifier(name)
103
99
  elif name in _MODULE_EXPORTS_ATTRIBUTE:
104
100
  module = _importlib.import_module(_MODULE_EXPORTS_ATTRIBUTE[name])
105
101
  export = getattr(module, name)