pulse-framework 0.1.62__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 (126) hide show
  1. pulse/__init__.py +1493 -0
  2. pulse/_examples.py +29 -0
  3. pulse/app.py +1086 -0
  4. pulse/channel.py +607 -0
  5. pulse/cli/__init__.py +0 -0
  6. pulse/cli/cmd.py +575 -0
  7. pulse/cli/dependencies.py +181 -0
  8. pulse/cli/folder_lock.py +134 -0
  9. pulse/cli/helpers.py +271 -0
  10. pulse/cli/logging.py +102 -0
  11. pulse/cli/models.py +35 -0
  12. pulse/cli/packages.py +262 -0
  13. pulse/cli/processes.py +292 -0
  14. pulse/cli/secrets.py +39 -0
  15. pulse/cli/uvicorn_log_config.py +87 -0
  16. pulse/code_analysis.py +38 -0
  17. pulse/codegen/__init__.py +0 -0
  18. pulse/codegen/codegen.py +359 -0
  19. pulse/codegen/templates/__init__.py +0 -0
  20. pulse/codegen/templates/layout.py +106 -0
  21. pulse/codegen/templates/route.py +345 -0
  22. pulse/codegen/templates/routes_ts.py +42 -0
  23. pulse/codegen/utils.py +20 -0
  24. pulse/component.py +237 -0
  25. pulse/components/__init__.py +0 -0
  26. pulse/components/for_.py +83 -0
  27. pulse/components/if_.py +86 -0
  28. pulse/components/react_router.py +94 -0
  29. pulse/context.py +108 -0
  30. pulse/cookies.py +322 -0
  31. pulse/decorators.py +344 -0
  32. pulse/dom/__init__.py +0 -0
  33. pulse/dom/elements.py +1024 -0
  34. pulse/dom/events.py +445 -0
  35. pulse/dom/props.py +1250 -0
  36. pulse/dom/svg.py +0 -0
  37. pulse/dom/tags.py +328 -0
  38. pulse/dom/tags.pyi +480 -0
  39. pulse/env.py +178 -0
  40. pulse/form.py +538 -0
  41. pulse/helpers.py +541 -0
  42. pulse/hooks/__init__.py +0 -0
  43. pulse/hooks/core.py +452 -0
  44. pulse/hooks/effects.py +88 -0
  45. pulse/hooks/init.py +668 -0
  46. pulse/hooks/runtime.py +464 -0
  47. pulse/hooks/setup.py +254 -0
  48. pulse/hooks/stable.py +138 -0
  49. pulse/hooks/state.py +192 -0
  50. pulse/js/__init__.py +125 -0
  51. pulse/js/__init__.pyi +115 -0
  52. pulse/js/_types.py +299 -0
  53. pulse/js/array.py +339 -0
  54. pulse/js/console.py +50 -0
  55. pulse/js/date.py +119 -0
  56. pulse/js/document.py +145 -0
  57. pulse/js/error.py +140 -0
  58. pulse/js/json.py +66 -0
  59. pulse/js/map.py +97 -0
  60. pulse/js/math.py +69 -0
  61. pulse/js/navigator.py +79 -0
  62. pulse/js/number.py +57 -0
  63. pulse/js/obj.py +81 -0
  64. pulse/js/object.py +172 -0
  65. pulse/js/promise.py +172 -0
  66. pulse/js/pulse.py +115 -0
  67. pulse/js/react.py +495 -0
  68. pulse/js/regexp.py +57 -0
  69. pulse/js/set.py +124 -0
  70. pulse/js/string.py +38 -0
  71. pulse/js/weakmap.py +53 -0
  72. pulse/js/weakset.py +48 -0
  73. pulse/js/window.py +205 -0
  74. pulse/messages.py +202 -0
  75. pulse/middleware.py +471 -0
  76. pulse/plugin.py +96 -0
  77. pulse/proxy.py +242 -0
  78. pulse/py.typed +0 -0
  79. pulse/queries/__init__.py +0 -0
  80. pulse/queries/client.py +609 -0
  81. pulse/queries/common.py +101 -0
  82. pulse/queries/effect.py +55 -0
  83. pulse/queries/infinite_query.py +1418 -0
  84. pulse/queries/mutation.py +295 -0
  85. pulse/queries/protocol.py +136 -0
  86. pulse/queries/query.py +1314 -0
  87. pulse/queries/store.py +120 -0
  88. pulse/react_component.py +88 -0
  89. pulse/reactive.py +1208 -0
  90. pulse/reactive_extensions.py +1172 -0
  91. pulse/render_session.py +768 -0
  92. pulse/renderer.py +584 -0
  93. pulse/request.py +205 -0
  94. pulse/routing.py +598 -0
  95. pulse/serializer.py +279 -0
  96. pulse/state.py +556 -0
  97. pulse/test_helpers.py +15 -0
  98. pulse/transpiler/__init__.py +111 -0
  99. pulse/transpiler/assets.py +81 -0
  100. pulse/transpiler/builtins.py +1029 -0
  101. pulse/transpiler/dynamic_import.py +130 -0
  102. pulse/transpiler/emit_context.py +49 -0
  103. pulse/transpiler/errors.py +96 -0
  104. pulse/transpiler/function.py +611 -0
  105. pulse/transpiler/id.py +18 -0
  106. pulse/transpiler/imports.py +341 -0
  107. pulse/transpiler/js_module.py +336 -0
  108. pulse/transpiler/modules/__init__.py +33 -0
  109. pulse/transpiler/modules/asyncio.py +57 -0
  110. pulse/transpiler/modules/json.py +24 -0
  111. pulse/transpiler/modules/math.py +265 -0
  112. pulse/transpiler/modules/pulse/__init__.py +5 -0
  113. pulse/transpiler/modules/pulse/tags.py +250 -0
  114. pulse/transpiler/modules/typing.py +63 -0
  115. pulse/transpiler/nodes.py +1987 -0
  116. pulse/transpiler/py_module.py +135 -0
  117. pulse/transpiler/transpiler.py +1100 -0
  118. pulse/transpiler/vdom.py +256 -0
  119. pulse/types/__init__.py +0 -0
  120. pulse/types/event_handler.py +50 -0
  121. pulse/user_session.py +386 -0
  122. pulse/version.py +69 -0
  123. pulse_framework-0.1.62.dist-info/METADATA +198 -0
  124. pulse_framework-0.1.62.dist-info/RECORD +126 -0
  125. pulse_framework-0.1.62.dist-info/WHEEL +4 -0
  126. pulse_framework-0.1.62.dist-info/entry_points.txt +3 -0
pulse/js/date.py ADDED
@@ -0,0 +1,119 @@
1
+ """
2
+ JavaScript Date builtin module.
3
+
4
+ Usage:
5
+
6
+ ```python
7
+ from pulse.js import Date
8
+ Date() # -> new Date()
9
+ Date.now() # -> Date.now()
10
+ Date.parse("2023-01-01") # -> Date.parse("2023-01-01")
11
+
12
+ # Or import from module directly:
13
+ from pulse.js.date import Date
14
+ ```
15
+ """
16
+
17
+ from typing import Any as _Any
18
+
19
+ from pulse.transpiler.js_module import JsModule
20
+
21
+
22
+ class Date:
23
+ """Class for JavaScript Date instances."""
24
+
25
+ def __init__(self, value: int | str | None = None, /): ...
26
+
27
+ @staticmethod
28
+ def now() -> float: ...
29
+
30
+ @staticmethod
31
+ def parse(dateString: str) -> float: ...
32
+
33
+ @staticmethod
34
+ def UTC(
35
+ year: int,
36
+ month: int,
37
+ date: int | None = None,
38
+ hours: int | None = None,
39
+ minutes: int | None = None,
40
+ seconds: int | None = None,
41
+ ms: int | None = None,
42
+ /,
43
+ ) -> float: ...
44
+
45
+ def getDate(self) -> int: ...
46
+ def getDay(self) -> int: ...
47
+ def getFullYear(self) -> int: ...
48
+ def getHours(self) -> int: ...
49
+ def getMilliseconds(self) -> int: ...
50
+ def getMinutes(self) -> int: ...
51
+ def getMonth(self) -> int: ...
52
+ def getSeconds(self) -> int: ...
53
+ def getTime(self) -> float: ...
54
+ def getTimezoneOffset(self) -> int: ...
55
+ def getUTCDate(self) -> int: ...
56
+ def getUTCDay(self) -> int: ...
57
+ def getUTCFullYear(self) -> int: ...
58
+ def getUTCHours(self) -> int: ...
59
+ def getUTCMilliseconds(self) -> int: ...
60
+ def getUTCMinutes(self) -> int: ...
61
+ def getUTCMonth(self) -> int: ...
62
+ def getUTCSeconds(self) -> int: ...
63
+ def setDate(self, date: int) -> float: ...
64
+ def setFullYear(
65
+ self, year: int, month: int | None = None, date: int | None = None, /
66
+ ) -> float: ...
67
+ def setHours(
68
+ self,
69
+ hours: int,
70
+ min: int | None = None,
71
+ sec: int | None = None,
72
+ ms: int | None = None,
73
+ /,
74
+ ) -> float: ...
75
+ def setMilliseconds(self, ms: int) -> float: ...
76
+ def setMinutes(
77
+ self, min: int, sec: int | None = None, ms: int | None = None, /
78
+ ) -> float: ...
79
+ def setMonth(self, month: int, date: int | None = None, /) -> float: ...
80
+ def setSeconds(self, sec: int, ms: int | None = None, /) -> float: ...
81
+ def setTime(self, time: float) -> float: ...
82
+ def setUTCDate(self, date: int) -> float: ...
83
+ def setUTCFullYear(
84
+ self, year: int, month: int | None = None, date: int | None = None
85
+ ) -> float: ...
86
+ def setUTCHours(
87
+ self,
88
+ hours: int,
89
+ min: int | None = None,
90
+ sec: int | None = None,
91
+ ms: int | None = None,
92
+ /,
93
+ ) -> float: ...
94
+ def setUTCMilliseconds(self, ms: int) -> float: ...
95
+ def setUTCMinutes(
96
+ self, min: int, sec: int | None = None, ms: int | None = None, /
97
+ ) -> float: ...
98
+ def setUTCMonth(self, month: int, date: int | None = None, /) -> float: ...
99
+ def setUTCSeconds(self, sec: int, ms: int | None = None, /) -> float: ...
100
+ def toDateString(self) -> str: ...
101
+ def toISOString(self) -> str: ...
102
+ def toJSON(self, key: _Any | None = None, /) -> str: ...
103
+ def toLocaleDateString(
104
+ self, locales: str | None = None, options: _Any | None = None, /
105
+ ) -> str: ...
106
+ def toLocaleString(
107
+ self, locales: str | None = None, options: _Any | None = None, /
108
+ ) -> str: ...
109
+ def toLocaleTimeString(
110
+ self, locales: str | None = None, options: _Any | None = None, /
111
+ ) -> str: ...
112
+ def toString(self) -> str: ...
113
+ def toTimeString(self) -> str: ...
114
+ def toUTCString(self) -> str: ...
115
+ def valueOf(self) -> float: ...
116
+
117
+
118
+ # Self-register this module as a JS builtin (global identifier)
119
+ JsModule.register(name=None)
pulse/js/document.py ADDED
@@ -0,0 +1,145 @@
1
+ """Browser document global object.
2
+
3
+ Usage:
4
+
5
+ ```python
6
+ from pulse.js import document
7
+ document.querySelector("#app") # -> document.querySelector("#app")
8
+ ```
9
+ """
10
+
11
+ from collections.abc import Callable as _Callable
12
+ from typing import Any as _Any
13
+
14
+ from pulse.js._types import Element as _Element
15
+ from pulse.js._types import HTMLCollection as _HTMLCollection
16
+ from pulse.js._types import HTMLElement as _HTMLElement
17
+ from pulse.js._types import NodeList as _NodeList
18
+ from pulse.transpiler.js_module import JsModule
19
+
20
+ # Read-only properties
21
+ body: _HTMLElement
22
+ head: _HTMLElement
23
+ documentElement: _HTMLElement
24
+ activeElement: _Element | None
25
+ title: str
26
+ readyState: str # "loading" | "interactive" | "complete"
27
+ cookie: str
28
+ referrer: str
29
+ URL: str
30
+ domain: str
31
+
32
+
33
+ # Query methods
34
+ def querySelector(selectors: str) -> _Element | None:
35
+ """Return the first element matching the selector, or None."""
36
+ ...
37
+
38
+
39
+ def querySelectorAll(selectors: str) -> _NodeList[_Element]:
40
+ """Return all elements matching the selector."""
41
+ ...
42
+
43
+
44
+ def getElementById(elementId: str) -> _Element | None:
45
+ """Return the element with the given ID, or None."""
46
+ ...
47
+
48
+
49
+ def getElementsByClassName(classNames: str) -> _HTMLCollection[_Element]:
50
+ """Return all elements with the given class name(s)."""
51
+ ...
52
+
53
+
54
+ def getElementsByTagName(qualifiedName: str) -> _HTMLCollection[_Element]:
55
+ """Return all elements with the given tag name."""
56
+ ...
57
+
58
+
59
+ def getElementsByName(elementName: str) -> _NodeList[_Element]:
60
+ """Return all elements with the given name attribute."""
61
+ ...
62
+
63
+
64
+ # Element creation
65
+ def createElement(
66
+ tagName: str, options: dict[str, str] | None = None, /
67
+ ) -> _HTMLElement:
68
+ """Create a new element with the given tag name."""
69
+ ...
70
+
71
+
72
+ def createTextNode(data: str) -> _Any:
73
+ """Create a new text node."""
74
+ ...
75
+
76
+
77
+ def createDocumentFragment() -> _Any:
78
+ """Create a new document fragment."""
79
+ ...
80
+
81
+
82
+ def createComment(data: str) -> _Any:
83
+ """Create a new comment node."""
84
+ ...
85
+
86
+
87
+ # Event methods
88
+ def addEventListener(
89
+ type: str,
90
+ listener: _Callable[..., None],
91
+ options: bool | dict[str, bool] | None = None,
92
+ /,
93
+ ) -> None:
94
+ """Add an event listener to the document."""
95
+ ...
96
+
97
+
98
+ def removeEventListener(
99
+ type: str,
100
+ listener: _Callable[..., None],
101
+ options: bool | dict[str, bool] | None = None,
102
+ /,
103
+ ) -> None:
104
+ """Remove an event listener from the document."""
105
+ ...
106
+
107
+
108
+ def dispatchEvent(event: _Any) -> bool:
109
+ """Dispatch an event to the document."""
110
+ ...
111
+
112
+
113
+ # Focus methods
114
+ def hasFocus() -> bool:
115
+ """Return True if the document has focus."""
116
+ ...
117
+
118
+
119
+ # Selection
120
+ def getSelection() -> _Any:
121
+ """Return the current selection."""
122
+ ...
123
+
124
+
125
+ # Node tree methods
126
+ def importNode(node: _Element, deep: bool = False, /) -> _Element:
127
+ """Import a node from another document."""
128
+ ...
129
+
130
+
131
+ def adoptNode(node: _Element) -> _Element:
132
+ """Adopt a node from another document."""
133
+ ...
134
+
135
+
136
+ # Full-screen API
137
+ def exitFullscreen() -> _Any:
138
+ """Exit full-screen mode. Returns a Promise."""
139
+ ...
140
+
141
+
142
+ fullscreenElement: _Element | None
143
+
144
+
145
+ JsModule.register(name="document")
pulse/js/error.py ADDED
@@ -0,0 +1,140 @@
1
+ """
2
+ JavaScript Error builtin module.
3
+
4
+ Usage:
5
+
6
+ ```python
7
+ from pulse.js import Error
8
+ Error("message") # -> new Error("message")
9
+
10
+ from pulse.js.error import TypeError, RangeError, ReferenceError
11
+ TypeError("message") # -> new TypeError("message")
12
+ ```
13
+ """
14
+
15
+ from pulse.transpiler.js_module import JsModule
16
+
17
+
18
+ class Error:
19
+ """Class for JavaScript Error instances."""
20
+
21
+ def __init__(self, message: str | None = None, /): ...
22
+
23
+ @property
24
+ def message(self) -> str: ...
25
+
26
+ @property
27
+ def name(self) -> str: ...
28
+
29
+ @property
30
+ def stack(self) -> str | None: ...
31
+
32
+ def toString(self) -> str: ...
33
+
34
+
35
+ # Error Subclasses - these are separate globals in JS, not members of Error
36
+ # TODO: These need a different architecture (separate modules or standalone identifiers)
37
+ class EvalError:
38
+ """Class for JavaScript EvalError instances."""
39
+
40
+ def __init__(self, message: str | None = None, /): ...
41
+
42
+ @property
43
+ def message(self) -> str: ...
44
+
45
+ @property
46
+ def name(self) -> str: ...
47
+
48
+ @property
49
+ def stack(self) -> str | None: ...
50
+
51
+ def toString(self) -> str: ...
52
+
53
+
54
+ class RangeError:
55
+ """Class for JavaScript RangeError instances."""
56
+
57
+ def __init__(self, message: str | None = None, /): ...
58
+
59
+ @property
60
+ def message(self) -> str: ...
61
+
62
+ @property
63
+ def name(self) -> str: ...
64
+
65
+ @property
66
+ def stack(self) -> str | None: ...
67
+
68
+ def toString(self) -> str: ...
69
+
70
+
71
+ class ReferenceError:
72
+ """Class for JavaScript ReferenceError instances."""
73
+
74
+ def __init__(self, message: str | None = None, /): ...
75
+
76
+ @property
77
+ def message(self) -> str: ...
78
+
79
+ @property
80
+ def name(self) -> str: ...
81
+
82
+ @property
83
+ def stack(self) -> str | None: ...
84
+
85
+ def toString(self) -> str: ...
86
+
87
+
88
+ class SyntaxError:
89
+ """Class for JavaScript SyntaxError instances."""
90
+
91
+ def __init__(self, message: str | None = None, /): ...
92
+
93
+ @property
94
+ def message(self) -> str: ...
95
+
96
+ @property
97
+ def name(self) -> str: ...
98
+
99
+ @property
100
+ def stack(self) -> str | None: ...
101
+
102
+ def toString(self) -> str: ...
103
+
104
+
105
+ class TypeError:
106
+ """Class for JavaScript TypeError instances."""
107
+
108
+ def __init__(self, message: str | None = None, /): ...
109
+
110
+ @property
111
+ def message(self) -> str: ...
112
+
113
+ @property
114
+ def name(self) -> str: ...
115
+
116
+ @property
117
+ def stack(self) -> str | None: ...
118
+
119
+ def toString(self) -> str: ...
120
+
121
+
122
+ class URIError:
123
+ """Class for JavaScript URIError instances."""
124
+
125
+ def __init__(self, message: str | None = None, /): ...
126
+
127
+ @property
128
+ def message(self) -> str: ...
129
+
130
+ @property
131
+ def name(self) -> str: ...
132
+
133
+ @property
134
+ def stack(self) -> str | None: ...
135
+
136
+ def toString(self) -> str: ...
137
+
138
+
139
+ # Self-register this module as a JS builtin (global identifiers)
140
+ JsModule.register(name=None)
pulse/js/json.py ADDED
@@ -0,0 +1,66 @@
1
+ """
2
+ JavaScript JSON builtin module.
3
+
4
+ Usage:
5
+
6
+ ```python
7
+ import pulse.js.json as JSON
8
+ JSON.stringify({"a": 1}) # -> JSON.stringify({"a": 1})
9
+ JSON.parse('{"a": 1}') # -> JSON.parse('{"a": 1}')
10
+
11
+ from pulse.js.json import stringify, parse
12
+ stringify({"a": 1}) # -> JSON.stringify({"a": 1})
13
+ parse('{"a": 1}') # -> JSON.parse('{"a": 1}')
14
+ ```
15
+ """
16
+
17
+ from collections.abc import Callable as _Callable
18
+ from collections.abc import Sequence as _Sequence
19
+ from typing import TypeVar as _TypeVar
20
+
21
+ from pulse.transpiler.js_module import JsModule
22
+
23
+ # JSON types
24
+ JSONValue = None | bool | int | float | str | list["JSONValue"] | dict[str, "JSONValue"]
25
+ JSONReplacer = _Sequence[str | int] | _Callable[[str, JSONValue], JSONValue]
26
+ JSONReviver = _Callable[[str, JSONValue], JSONValue]
27
+
28
+ T = _TypeVar("T")
29
+
30
+
31
+ def parse(text: str, reviver: JSONReviver | None = None, /) -> JSONValue:
32
+ """Parse a JSON string into a JavaScript value.
33
+
34
+ Args:
35
+ text: The JSON string to parse.
36
+ reviver: Optional function (key: str, value: Any) -> Any that transforms the parsed value.
37
+ Called for each key-value pair. Return the value to use, or undefined to omit.
38
+
39
+ Returns:
40
+ The parsed JavaScript value (null, bool, number, string, array, or object).
41
+ """
42
+ ...
43
+
44
+
45
+ def stringify(
46
+ value: JSONValue,
47
+ replacer: JSONReplacer | None = None,
48
+ space: int | str | None = None,
49
+ /,
50
+ ) -> str:
51
+ """Convert a JavaScript value to a JSON string.
52
+
53
+ Args:
54
+ value: The value to convert to JSON.
55
+ replacer: Optional array of property names/indices, or function (key: str, value: Any) -> Any
56
+ that controls which properties are included. Return undefined to omit.
57
+ space: Optional indentation. Number for spaces per level, or string (up to 10 chars).
58
+
59
+ Returns:
60
+ The JSON string representation of the value.
61
+ """
62
+ ...
63
+
64
+
65
+ # Self-register this module as a JS builtin
66
+ JsModule.register(name="JSON")
pulse/js/map.py ADDED
@@ -0,0 +1,97 @@
1
+ """
2
+ JavaScript Map builtin module.
3
+
4
+ Usage:
5
+
6
+ ```python
7
+ from pulse.js import Map
8
+ Map() # -> new Map()
9
+ Map([["a", 1]]) # -> new Map([["a", 1]])
10
+
11
+ # Or import from module directly:
12
+ from pulse.js.map import Map
13
+ ```
14
+ """
15
+
16
+ from collections.abc import Callable as _Callable
17
+ from collections.abc import Iterable as _Iterable
18
+ from collections.abc import Iterator as _Iterator
19
+ from typing import Any as _Any
20
+ from typing import Generic as _Generic
21
+ from typing import TypeVar as _TypeVar
22
+
23
+ from pulse.transpiler.js_module import JsModule
24
+
25
+ K = _TypeVar("K")
26
+ V = _TypeVar("V")
27
+
28
+
29
+ class Map(_Generic[K, V]):
30
+ """JavaScript Map - a collection of keyed data items.
31
+
32
+ Map[K, V] preserves insertion order and allows keys of any type.
33
+ """
34
+
35
+ def __init__(self, iterable: _Iterable[tuple[K, V]] | None = None, /) -> None: ...
36
+
37
+ @property
38
+ def size(self) -> int:
39
+ """The number of key/value pairs in the Map."""
40
+ ...
41
+
42
+ def clear(self) -> None:
43
+ """Remove all key/value pairs."""
44
+ ...
45
+
46
+ def delete(self, key: K) -> bool:
47
+ """Remove a key and its value. Returns True if the key existed."""
48
+ ...
49
+
50
+ def get(self, key: K) -> V | None:
51
+ """Return the value for a key, or None if not present."""
52
+ ...
53
+
54
+ def has(self, key: K) -> bool:
55
+ """Return True if the key exists in the Map."""
56
+ ...
57
+
58
+ def set(self, key: K, value: V) -> "Map[K, V]":
59
+ """Set a key/value pair. Returns the Map for chaining."""
60
+ ...
61
+
62
+ def forEach(
63
+ self,
64
+ callback: _Callable[[V, K, "Map[K, V]"], None],
65
+ thisArg: _Any | None = None,
66
+ /,
67
+ ) -> None:
68
+ """Execute a function for each key/value pair."""
69
+ ...
70
+
71
+ def keys(self) -> _Iterable[K]:
72
+ """Return an iterator of keys."""
73
+ ...
74
+
75
+ def values(self) -> _Iterable[V]:
76
+ """Return an iterator of values."""
77
+ ...
78
+
79
+ def entries(self) -> _Iterable[tuple[K, V]]:
80
+ """Return an iterator of [key, value] pairs."""
81
+ ...
82
+
83
+ def __iter__(self) -> _Iterator[tuple[K, V]]:
84
+ """Iterate over [key, value] pairs."""
85
+ ...
86
+
87
+ def __len__(self) -> int:
88
+ """Return the number of key/value pairs (same as size)."""
89
+ ...
90
+
91
+ def __contains__(self, key: K) -> bool:
92
+ """Check if key exists in the Map (same as has)."""
93
+ ...
94
+
95
+
96
+ # Self-register this module as a JS builtin (global identifiers)
97
+ JsModule.register(name=None)
pulse/js/math.py ADDED
@@ -0,0 +1,69 @@
1
+ """
2
+ JavaScript Math builtin module.
3
+
4
+ Usage:
5
+
6
+ ```python
7
+ import pulse.js.math as Math
8
+ Math.PI # -> Math.PI
9
+ Math.floor(3.7) # -> Math.floor(3.7)
10
+
11
+ from pulse.js.math import PI, floor
12
+ PI # -> Math.PI
13
+ floor(3.7) # -> Math.floor(3.7)
14
+ ```
15
+ """
16
+
17
+ from pulse.transpiler.js_module import JsModule
18
+
19
+ # Constants (type stubs for IDE support)
20
+ PI: float
21
+ E: float
22
+ LN2: float
23
+ LN10: float
24
+ LOG2E: float
25
+ LOG10E: float
26
+ SQRT1_2: float
27
+ SQRT2: float
28
+
29
+
30
+ # Methods (type stubs for IDE support)
31
+ def abs(x: float) -> float: ...
32
+ def acos(x: float) -> float: ...
33
+ def acosh(x: float) -> float: ...
34
+ def asin(x: float) -> float: ...
35
+ def asinh(x: float) -> float: ...
36
+ def atan(x: float) -> float: ...
37
+ def atan2(y: float, x: float) -> float: ...
38
+ def atanh(x: float) -> float: ...
39
+ def cbrt(x: float) -> float: ...
40
+ def ceil(x: float) -> int: ...
41
+ def clz32(x: int) -> int: ...
42
+ def cos(x: float) -> float: ...
43
+ def cosh(x: float) -> float: ...
44
+ def exp(x: float) -> float: ...
45
+ def expm1(x: float) -> float: ...
46
+ def floor(x: float) -> int: ...
47
+ def fround(x: float) -> float: ...
48
+ def hypot(*values: float) -> float: ...
49
+ def imul(x: int, y: int) -> int: ...
50
+ def log(x: float) -> float: ...
51
+ def log10(x: float) -> float: ...
52
+ def log1p(x: float) -> float: ...
53
+ def log2(x: float) -> float: ...
54
+ def max(*values: float) -> float: ...
55
+ def min(*values: float) -> float: ...
56
+ def pow(x: float, y: float) -> float: ...
57
+ def random() -> float: ...
58
+ def round(x: float) -> int: ...
59
+ def sign(x: float) -> int: ...
60
+ def sin(x: float) -> float: ...
61
+ def sinh(x: float) -> float: ...
62
+ def sqrt(x: float) -> float: ...
63
+ def tan(x: float) -> float: ...
64
+ def tanh(x: float) -> float: ...
65
+ def trunc(x: float) -> int: ...
66
+
67
+
68
+ # Self-register this module as a JS builtin
69
+ JsModule.register(name="Math")
pulse/js/navigator.py ADDED
@@ -0,0 +1,79 @@
1
+ """Browser navigator global object.
2
+
3
+ Usage:
4
+
5
+ ```python
6
+ from pulse.js import navigator, console
7
+ console.log(navigator.userAgent)
8
+ ```
9
+ """
10
+
11
+ from typing import Any as _Any
12
+
13
+ from pulse.js._types import Clipboard as _Clipboard
14
+ from pulse.transpiler.js_module import JsModule
15
+
16
+ # User agent and browser info
17
+ userAgent: str
18
+ language: str
19
+ languages: list[str]
20
+ platform: str
21
+ vendor: str
22
+ appName: str
23
+ appVersion: str
24
+
25
+ # Online status
26
+ onLine: bool
27
+
28
+ # Hardware info
29
+ hardwareConcurrency: int
30
+ maxTouchPoints: int
31
+ deviceMemory: float | None # May not be available in all browsers
32
+
33
+ # Cookies
34
+ cookieEnabled: bool
35
+
36
+ # PDF viewer
37
+ pdfViewerEnabled: bool
38
+
39
+ # Clipboard API
40
+ clipboard: _Clipboard
41
+
42
+ # Media devices (typed as _Any for simplicity)
43
+ mediaDevices: _Any
44
+
45
+ # Permissions (typed as _Any for simplicity)
46
+ permissions: _Any
47
+
48
+ # Service worker (typed as _Any for simplicity)
49
+ serviceWorker: _Any
50
+
51
+ # Geolocation (typed as _Any for simplicity)
52
+ geolocation: _Any
53
+
54
+ # Storage
55
+ storage: _Any
56
+
57
+
58
+ # Methods
59
+ def vibrate(pattern: int | list[int]) -> bool:
60
+ """Vibrate the device. Returns True if vibration is supported."""
61
+ ...
62
+
63
+
64
+ def share(data: dict[str, str]) -> _Any:
65
+ """Share data via the Web Share API. Returns a Promise."""
66
+ ...
67
+
68
+
69
+ def sendBeacon(url: str, data: str | bytes | _Any | None = None, /) -> bool:
70
+ """Send data to a URL asynchronously. Returns True if successful."""
71
+ ...
72
+
73
+
74
+ def canShare(data: dict[str, str] | None = None, /) -> bool:
75
+ """Check if data can be shared via the Web Share API."""
76
+ ...
77
+
78
+
79
+ JsModule.register(name="navigator")