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/routing.py CHANGED
@@ -3,10 +3,9 @@ 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.component import Component
6
7
  from pulse.env import env
7
- from pulse.react_component import ReactComponent
8
8
  from pulse.reactive_extensions import ReactiveDict
9
- from pulse.vdom import Component
10
9
 
11
10
  # angle brackets cannot appear in a regular URL path, this ensures no name conflicts
12
11
  LAYOUT_INDICATOR = "<layout>"
@@ -158,7 +157,6 @@ class Route:
158
157
  segments: list[PathSegment]
159
158
  render: Component[[]]
160
159
  children: Sequence["Route | Layout"]
161
- components: Sequence[ReactComponent[...]] | None
162
160
  is_index: bool
163
161
  is_dynamic: bool
164
162
  dev: bool
@@ -168,7 +166,6 @@ class Route:
168
166
  path: str,
169
167
  render: Component[[]],
170
168
  children: "Sequence[Route | Layout] | None" = None,
171
- components: "Sequence[ReactComponent[...]] | None" = None,
172
169
  dev: bool = False,
173
170
  ):
174
171
  self.path = ensure_relative_path(path)
@@ -176,7 +173,6 @@ class Route:
176
173
 
177
174
  self.render = render
178
175
  self.children = children or []
179
- self.components = components
180
176
  self.dev = dev
181
177
  self.parent: Route | Layout | None = None
182
178
 
@@ -249,19 +245,16 @@ def replace_layout_indicator(path_list: list[str], value: str):
249
245
  class Layout:
250
246
  render: Component[...]
251
247
  children: Sequence["Route | Layout"]
252
- components: Sequence[ReactComponent[...]] | None
253
248
  dev: bool
254
249
 
255
250
  def __init__(
256
251
  self,
257
252
  render: "Component[...]",
258
253
  children: "Sequence[Route | Layout] | None" = None,
259
- components: "Sequence[ReactComponent[...]] | None" = None,
260
254
  dev: bool = False,
261
255
  ):
262
256
  self.render = render
263
257
  self.children = children or []
264
- self.components = components
265
258
  self.dev = dev
266
259
  self.parent: Route | Layout | None = None
267
260
  # 1-based sibling index assigned by RouteTree at each level
@@ -352,14 +345,12 @@ def filter_dev_routes(routes: Sequence[Route | Layout]) -> list[Route | Layout]:
352
345
  path=route.path,
353
346
  render=route.render,
354
347
  children=filtered_children,
355
- components=route.components,
356
348
  dev=route.dev,
357
349
  )
358
350
  else: # Layout
359
351
  filtered_route = Layout(
360
352
  render=route.render,
361
353
  children=filtered_children,
362
- components=route.components,
363
354
  dev=route.dev,
364
355
  )
365
356
  filtered.append(filtered_route)
pulse/serializer.py CHANGED
@@ -29,6 +29,7 @@ containing primitives, lists/tuples, ``dict``/plain objects, ``set`` and
29
29
  from __future__ import annotations
30
30
 
31
31
  import datetime as dt
32
+ import math
32
33
  import types
33
34
  from dataclasses import fields, is_dataclass
34
35
  from typing import Any
@@ -56,7 +57,16 @@ def serialize(data: Any) -> Serialized:
56
57
 
57
58
  def process(value: Any) -> PlainJSON:
58
59
  nonlocal global_index
59
- if value is None or isinstance(value, (bool, int, float, str)):
60
+ if value is None or isinstance(value, (bool, int, str)):
61
+ return value
62
+ if isinstance(value, float):
63
+ if math.isnan(value):
64
+ return None # NaN → None (matches pandas None ↔ NaN semantics)
65
+ if math.isinf(value):
66
+ raise ValueError(
67
+ f"Cannot serialize {value}: Infinity is not valid JSON. "
68
+ + "Replace with None or a sentinel value."
69
+ )
60
70
  return value
61
71
 
62
72
  idx = global_index
@@ -1,131 +1,101 @@
1
- """Python -> JavaScript transpiler system.
1
+ """v2 transpiler with pure data node AST."""
2
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:
3
+ # Ensure built-in Python modules (e.g., math) are registered on import.
4
+ from pulse.transpiler import modules as _modules # noqa: F401
5
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
6
+ # Builtins
17
7
  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
8
  from pulse.transpiler.builtins import emit_method as emit_method
29
9
 
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
10
+ # Errors
11
+ from pulse.transpiler.errors import TranspileError as TranspileError
43
12
 
44
13
  # Function system
45
14
  from pulse.transpiler.function import FUNCTION_CACHE as FUNCTION_CACHE
15
+
16
+ # Constant hoisting
17
+ from pulse.transpiler.function import Constant as Constant
46
18
  from pulse.transpiler.function import JsFunction as JsFunction
19
+ from pulse.transpiler.function import analyze_deps as analyze_deps
20
+ from pulse.transpiler.function import clear_function_cache as clear_function_cache
21
+ from pulse.transpiler.function import (
22
+ collect_function_graph as collect_function_graph,
23
+ )
47
24
  from pulse.transpiler.function import javascript as javascript
25
+ from pulse.transpiler.function import registered_constants as registered_constants
26
+ from pulse.transpiler.function import registered_functions as registered_functions
48
27
 
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
28
+ # ID generator
29
+ from pulse.transpiler.id import next_id as next_id
30
+ from pulse.transpiler.id import reset_id_counter as reset_id_counter
54
31
 
55
- # Import system
32
+ # Import utilities
33
+ from pulse.transpiler.imports import Import as Import
34
+ from pulse.transpiler.imports import ImportKind as ImportKind
35
+ from pulse.transpiler.imports import caller_file as caller_file
56
36
  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
37
+ from pulse.transpiler.imports import get_registered_imports as get_registered_imports
38
+ from pulse.transpiler.imports import is_absolute_path as is_absolute_path
39
+ from pulse.transpiler.imports import is_local_path as is_local_path
40
+ from pulse.transpiler.imports import is_relative_path as is_relative_path
59
41
 
60
- # Module registration - JS modules
61
- from pulse.transpiler.js_module import JS_MODULES as JS_MODULES
42
+ # JS module system
62
43
  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
44
+
45
+ # Global registry
46
+ from pulse.transpiler.nodes import EXPR_REGISTRY as EXPR_REGISTRY
47
+ from pulse.transpiler.nodes import UNDEFINED as UNDEFINED
48
+
49
+ # Expression nodes
50
+ from pulse.transpiler.nodes import Array as Array
51
+ from pulse.transpiler.nodes import Arrow as Arrow
52
+
53
+ # Statement nodes
54
+ from pulse.transpiler.nodes import Assign as Assign
55
+ from pulse.transpiler.nodes import Binary as Binary
56
+ from pulse.transpiler.nodes import Block as Block
57
+ from pulse.transpiler.nodes import Break as Break
58
+ from pulse.transpiler.nodes import Call as Call
59
+
60
+ # Type aliases
61
+ from pulse.transpiler.nodes import Continue as Continue
62
+
63
+ # Data nodes
64
+ from pulse.transpiler.nodes import Element as Element
65
+ from pulse.transpiler.nodes import Expr as Expr
66
+ from pulse.transpiler.nodes import ExprStmt as ExprStmt
67
+ from pulse.transpiler.nodes import ForOf as ForOf
68
+ from pulse.transpiler.nodes import Function as Function
69
+ from pulse.transpiler.nodes import Identifier as Identifier
70
+ from pulse.transpiler.nodes import If as If
71
+
72
+ # JSX wrapper
73
+ from pulse.transpiler.nodes import Jsx as Jsx
74
+ from pulse.transpiler.nodes import Literal as Literal
75
+ from pulse.transpiler.nodes import Member as Member
76
+ from pulse.transpiler.nodes import New as New
77
+ from pulse.transpiler.nodes import Node as Node
78
+ from pulse.transpiler.nodes import Object as Object
79
+ from pulse.transpiler.nodes import Prop as Prop
80
+ from pulse.transpiler.nodes import PulseNode as PulseNode
81
+ from pulse.transpiler.nodes import Return as Return
82
+ from pulse.transpiler.nodes import Spread as Spread
83
+ from pulse.transpiler.nodes import Stmt as Stmt
84
+ from pulse.transpiler.nodes import Subscript as Subscript
85
+ from pulse.transpiler.nodes import Template as Template
86
+ from pulse.transpiler.nodes import Ternary as Ternary
87
+ from pulse.transpiler.nodes import Throw as Throw
88
+ from pulse.transpiler.nodes import Unary as Unary
89
+ from pulse.transpiler.nodes import Undefined as Undefined
90
+ from pulse.transpiler.nodes import Value as Value
91
+ from pulse.transpiler.nodes import While as While
92
+
93
+ # Emit
94
+ from pulse.transpiler.nodes import emit as emit
95
+
96
+ # React components (JSX imports with typed call signature)
97
+ from pulse.transpiler.react_component import react_component as react_component
129
98
 
130
99
  # Transpiler
131
- from pulse.transpiler.transpiler import JsTranspiler as JsTranspiler
100
+ from pulse.transpiler.transpiler import Transpiler as Transpiler
101
+ from pulse.transpiler.transpiler import transpile as transpile