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
pulse/js/object.py ADDED
@@ -0,0 +1,173 @@
1
+ """
2
+ JavaScript Object builtin module.
3
+
4
+ Usage:
5
+ import pulse.js.object as Object
6
+ Object.keys({"a": 1}) # -> Object.keys({"a": 1})
7
+ Object.assign({}, {"a": 1}) # -> Object.assign({}, {"a": 1})
8
+ Object.is(x, y) # -> Object.is(x, y)
9
+
10
+ # Note: For 'is' (Python keyword), use namespace import:
11
+ # import pulse.js.object as Object; Object.is(...)
12
+ # Or use the underscore version for direct import:
13
+ from pulse.js.object import keys, assign, is_
14
+ keys({"a": 1}) # -> Object.keys({"a": 1})
15
+ assign({}, {"a": 1}) # -> Object.assign({}, {"a": 1})
16
+ is_(x, y) # -> Object.is(x, y)
17
+ """
18
+
19
+ from collections.abc import Iterable as _Iterable
20
+ from typing import Any as _Any
21
+ from typing import TypedDict as _TypedDict
22
+ from typing import TypeVar as _TypeVar
23
+
24
+ from pulse.transpiler.js_module import register_js_module as _register_js_module
25
+
26
+ T = _TypeVar("T")
27
+ K = _TypeVar("K", bound=str) # Object keys are always strings in JS
28
+
29
+
30
+ # Property descriptor type - JS uses a plain object with specific keys
31
+ class PropertyDescriptor(_TypedDict, total=False):
32
+ """Type for Object.defineProperty descriptor."""
33
+
34
+ value: _Any
35
+ writable: bool
36
+ get: _Any # Callable[[], T] but we use _Any for flexibility
37
+ set: _Any # Callable[[T], None]
38
+ configurable: bool
39
+ enumerable: bool
40
+
41
+
42
+ class Object:
43
+ """JavaScript Object namespace - static methods for object manipulation.
44
+
45
+ Note: Object is primarily used as a namespace for static methods.
46
+ The types here are as precise as JavaScript's dynamic nature allows.
47
+ """
48
+
49
+ @staticmethod
50
+ def assign(target: T, *sources: _Any) -> T:
51
+ """Copy properties from sources to target. Returns target."""
52
+ ...
53
+
54
+ @staticmethod
55
+ def create(
56
+ proto: _Any | None,
57
+ propertiesObject: dict[str, PropertyDescriptor] | None = None,
58
+ ) -> _Any:
59
+ """Create a new object with the specified prototype."""
60
+ ...
61
+
62
+ @staticmethod
63
+ def defineProperty(
64
+ obj: T, prop: str, descriptor: PropertyDescriptor | dict[str, _Any]
65
+ ) -> T:
66
+ """Define a property on an object. Returns the object."""
67
+ ...
68
+
69
+ @staticmethod
70
+ def defineProperties(
71
+ obj: T, props: dict[str, PropertyDescriptor | dict[str, _Any]]
72
+ ) -> T:
73
+ """Define multiple properties on an object. Returns the object."""
74
+ ...
75
+
76
+ @staticmethod
77
+ def entries(obj: dict[str, T]) -> list[tuple[str, T]]:
78
+ """Return an array of [key, value] pairs."""
79
+ ...
80
+
81
+ @staticmethod
82
+ def freeze(obj: T) -> T:
83
+ """Freeze an object (prevent modifications). Returns the object."""
84
+ ...
85
+
86
+ @staticmethod
87
+ def fromEntries(entries: _Iterable[tuple[str, T]]) -> dict[str, T]:
88
+ """Create an object from an iterable of [key, value] pairs."""
89
+ ...
90
+
91
+ @staticmethod
92
+ def getOwnPropertyDescriptor(obj: _Any, prop: str) -> PropertyDescriptor | None:
93
+ """Return the property descriptor for a property."""
94
+ ...
95
+
96
+ @staticmethod
97
+ def getOwnPropertyDescriptors(obj: _Any) -> dict[str, PropertyDescriptor]:
98
+ """Return all own property descriptors."""
99
+ ...
100
+
101
+ @staticmethod
102
+ def getOwnPropertyNames(obj: _Any) -> list[str]:
103
+ """Return all own property names (including non-enumerable)."""
104
+ ...
105
+
106
+ @staticmethod
107
+ def getOwnPropertySymbols(obj: _Any) -> list[_Any]:
108
+ """Return all own Symbol properties."""
109
+ ...
110
+
111
+ @staticmethod
112
+ def getPrototypeOf(obj: _Any) -> _Any | None:
113
+ """Return the prototype of an object."""
114
+ ...
115
+
116
+ @staticmethod
117
+ def hasOwn(obj: _Any, prop: str) -> bool:
118
+ """Return True if the object has the specified own property."""
119
+ ...
120
+
121
+ @staticmethod
122
+ def is_(value1: _Any, value2: _Any) -> bool:
123
+ """Determine if two values are the same value (SameValue algorithm)."""
124
+ ...
125
+
126
+ @staticmethod
127
+ def isExtensible(obj: _Any) -> bool:
128
+ """Return True if the object is extensible."""
129
+ ...
130
+
131
+ @staticmethod
132
+ def isFrozen(obj: _Any) -> bool:
133
+ """Return True if the object is frozen."""
134
+ ...
135
+
136
+ @staticmethod
137
+ def isSealed(obj: _Any) -> bool:
138
+ """Return True if the object is sealed."""
139
+ ...
140
+
141
+ @staticmethod
142
+ def keys(obj: dict[str, _Any]) -> list[str]:
143
+ """Return an array of enumerable property names."""
144
+ ...
145
+
146
+ @staticmethod
147
+ def preventExtensions(obj: T) -> T:
148
+ """Prevent new properties from being added. Returns the object."""
149
+ ...
150
+
151
+ @staticmethod
152
+ def seal(obj: T) -> T:
153
+ """Seal an object (prevent adding/removing properties). Returns the object."""
154
+ ...
155
+
156
+ @staticmethod
157
+ def setPrototypeOf(obj: T, prototype: _Any | None) -> T:
158
+ """Set the prototype of an object. Returns the object."""
159
+ ...
160
+
161
+ @staticmethod
162
+ def values(obj: dict[str, T]) -> list[T]:
163
+ """Return an array of enumerable property values."""
164
+ ...
165
+
166
+ @staticmethod
167
+ def groupBy(items: _Iterable[T], keyFn: _Any) -> dict[str, list[T]]:
168
+ """Group items by key function result (ES2024)."""
169
+ ...
170
+
171
+
172
+ # Self-register this module as a JS builtin
173
+ _register_js_module(name="Object", global_scope=True)
pulse/js/promise.py ADDED
@@ -0,0 +1,150 @@
1
+ """
2
+ JavaScript Promise builtin module.
3
+
4
+ Usage:
5
+ import pulse.js.promise as Promise
6
+ Promise.resolve(value) # -> Promise.resolve(value)
7
+ Promise.reject(reason) # -> Promise.reject(reason)
8
+
9
+ from pulse.js.promise import resolve, reject, all, allSettled, race, any
10
+ resolve(value) # -> Promise.resolve(value)
11
+ reject(reason) # -> Promise.reject(reason)
12
+
13
+ The Promise class is generic and supports async/await via the Awaitable protocol.
14
+ """
15
+
16
+ from collections.abc import Callable as _Callable
17
+ from collections.abc import Generator as _Generator
18
+ from collections.abc import Iterable as _Iterable
19
+ from typing import Generic as _Generic
20
+ from typing import TypeVar as _TypeVar
21
+
22
+ from pulse.transpiler.js_module import register_js_module as _register_js_module
23
+
24
+ T = _TypeVar("T")
25
+ T_co = _TypeVar("T_co", covariant=True)
26
+ U = _TypeVar("U")
27
+
28
+ # Result types for allSettled
29
+ PromiseFulfilledResult = dict[str, T | str] # { status: "fulfilled", value: T }
30
+ PromiseRejectedResult = dict[str, str] # { status: "rejected", reason: any }
31
+ PromiseSettledResult = PromiseFulfilledResult[T] | PromiseRejectedResult
32
+
33
+
34
+ class Promise(_Generic[T_co]):
35
+ """JavaScript Promise - a thenable that represents an async operation.
36
+
37
+ Promise is both generic over its resolved type and implements Awaitable,
38
+ allowing it to be used with Python's async/await syntax which transpiles
39
+ to JavaScript async/await.
40
+
41
+ Example:
42
+ @javascript
43
+ async def fetch_data() -> str:
44
+ response: Promise[Response] = fetch("/api/data")
45
+ data = await response # Awaits the promise
46
+ return data.text()
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ executor: _Callable[
52
+ [_Callable[[T_co], None], _Callable[[Exception], None]], None
53
+ ]
54
+ | None = None,
55
+ ) -> None:
56
+ """Create a Promise.
57
+
58
+ Args:
59
+ executor: Optional function receiving (resolve, reject) callbacks.
60
+ If omitted, creates a pending promise (for use with Promise.resolve/reject).
61
+ """
62
+ ...
63
+
64
+ def then(
65
+ self,
66
+ on_fulfilled: _Callable[[T_co], U | "Promise[U]"] | None = None,
67
+ on_rejected: _Callable[[Exception], U | "Promise[U]"] | None = None,
68
+ ) -> "Promise[U]":
69
+ """Attach callbacks to handle fulfillment and/or rejection."""
70
+ ...
71
+
72
+ def catch(
73
+ self, on_rejected: _Callable[[Exception], U | "Promise[U]"]
74
+ ) -> "Promise[T_co | U]":
75
+ """Attach a rejection handler callback."""
76
+ ...
77
+
78
+ def finally_(self, on_finally: _Callable[[], None]) -> "Promise[T_co]":
79
+ """Attach a handler that is called when the promise settles (fulfilled or rejected)."""
80
+ ...
81
+
82
+ def __await__(self) -> _Generator[None, None, T_co]:
83
+ """Support await syntax - transpiles to JavaScript await."""
84
+ ...
85
+
86
+ # Static methods for Promise construction
87
+ @staticmethod
88
+ def resolve(value: U | None = None) -> "Promise[U] | Promise[None]":
89
+ """Create a Promise that resolves with the given value."""
90
+ ...
91
+
92
+ @staticmethod
93
+ def reject(reason: Exception | str) -> "Promise[T]":
94
+ """Create a Promise that rejects with the given reason."""
95
+ ...
96
+
97
+ # Static methods for combining promises
98
+ @staticmethod
99
+ def all(iterable: _Iterable["Promise[T]"]) -> "Promise[list[T]]":
100
+ """Wait for all promises to resolve, or reject on first rejection.
101
+
102
+ Returns a promise that resolves to a list of all resolved values.
103
+ """
104
+ ...
105
+
106
+ @staticmethod
107
+ def allSettled(
108
+ iterable: _Iterable["Promise[T]"],
109
+ ) -> "Promise[list[PromiseSettledResult[T]]]":
110
+ """Wait for all promises to settle (resolve or reject).
111
+
112
+ Returns a promise that resolves to a list of result objects.
113
+ """
114
+ ...
115
+
116
+ @staticmethod
117
+ def any(iterable: _Iterable["Promise[T]"]) -> "Promise[T]":
118
+ """Return first fulfilled promise, or reject if all reject."""
119
+ ...
120
+
121
+ @staticmethod
122
+ def race(iterable: _Iterable["Promise[T]"]) -> "Promise[T]":
123
+ """Return first settled promise (fulfilled or rejected)."""
124
+ ...
125
+
126
+ @staticmethod
127
+ def withResolvers() -> "PromiseWithResolvers[T]":
128
+ """Create a promise with its resolve and reject functions exposed.
129
+
130
+ Returns an object with { promise, resolve, reject }.
131
+ ES2024 feature.
132
+ """
133
+ ...
134
+
135
+
136
+ class PromiseWithResolvers(_Generic[T]):
137
+ """Result type for Promise.withResolvers()."""
138
+
139
+ @property
140
+ def promise(self) -> Promise[T]: ...
141
+
142
+ @property
143
+ def resolve(self) -> _Callable[[T], None]: ...
144
+
145
+ @property
146
+ def reject(self) -> _Callable[[Exception | str], None]: ...
147
+
148
+
149
+ # Self-register this module as a JS builtin
150
+ _register_js_module(name="Promise", global_scope=True)
pulse/js/regexp.py ADDED
@@ -0,0 +1,54 @@
1
+ """
2
+ JavaScript RegExp builtin module.
3
+
4
+ Usage:
5
+ import pulse.js.regexp as RegExp
6
+ RegExp(pattern, flags) # -> new RegExp(pattern, flags)
7
+
8
+ from pulse.js.regexp import RegExp
9
+ RegExp(pattern, flags) # -> new RegExp(pattern, flags)
10
+ """
11
+
12
+ from pulse.transpiler.js_module import register_js_module as _register_js_module
13
+
14
+
15
+ class RegExp:
16
+ """Class for JavaScript RegExp instances."""
17
+
18
+ def __init__(self, pattern: str, flags: str | None = None): ...
19
+
20
+ def exec(self, string: str) -> list[str] | None: ...
21
+ def test(self, string: str) -> bool: ...
22
+
23
+ @property
24
+ def source(self) -> str: ...
25
+
26
+ @property
27
+ def flags(self) -> str: ...
28
+
29
+ @property
30
+ def glob(self) -> bool: ... # JavaScript 'global' property
31
+
32
+ @property
33
+ def ignoreCase(self) -> bool: ...
34
+
35
+ @property
36
+ def multiline(self) -> bool: ...
37
+
38
+ @property
39
+ def dotAll(self) -> bool: ...
40
+
41
+ @property
42
+ def unicode(self) -> bool: ...
43
+
44
+ @property
45
+ def sticky(self) -> bool: ...
46
+
47
+ @property
48
+ def lastIndex(self) -> int: ...
49
+
50
+ def toString(self) -> str: ...
51
+
52
+
53
+ # Self-register this module as a JS builtin
54
+ _register_js_module(name="RegExp", global_scope=True)
pulse/js/set.py ADDED
@@ -0,0 +1,109 @@
1
+ """
2
+ JavaScript Set builtin module.
3
+
4
+ Usage:
5
+ import pulse.js.set as Set
6
+ Set() # -> new Set()
7
+ Set([1, 2, 3]) # -> new Set([1, 2, 3])
8
+
9
+ from pulse.js.set import Set
10
+ Set() # -> new Set()
11
+ """
12
+
13
+ from collections.abc import Callable as _Callable
14
+ from collections.abc import Iterable as _Iterable
15
+ from typing import Any as _Any
16
+ from typing import Generic as _Generic
17
+ from typing import TypeVar as _TypeVar
18
+
19
+ from pulse.transpiler.js_module import register_js_module as _register_js_module
20
+
21
+ T = _TypeVar("T")
22
+
23
+
24
+ class Set(_Generic[T]):
25
+ """JavaScript Set - a collection of unique values.
26
+
27
+ Set[T] stores unique values of type T in insertion order.
28
+ """
29
+
30
+ def __init__(self, iterable: _Iterable[T] | None = None) -> None: ...
31
+
32
+ @property
33
+ def size(self) -> int:
34
+ """The number of values in the Set."""
35
+ ...
36
+
37
+ def add(self, value: T) -> "Set[T]":
38
+ """Add a value to the Set. Returns the Set for chaining."""
39
+ ...
40
+
41
+ def clear(self) -> None:
42
+ """Remove all values from the Set."""
43
+ ...
44
+
45
+ def delete(self, value: T) -> bool:
46
+ """Remove a value. Returns True if the value existed."""
47
+ ...
48
+
49
+ def has(self, value: T) -> bool:
50
+ """Return True if the value exists in the Set."""
51
+ ...
52
+
53
+ def forEach(
54
+ self, callback: _Callable[[T, T, "Set[T]"], None], thisArg: _Any | None = None
55
+ ) -> None:
56
+ """Execute a function for each value.
57
+
58
+ Note: callback receives (value, value, set) for compatibility with Map.
59
+ """
60
+ ...
61
+
62
+ def keys(self) -> _Iterable[T]:
63
+ """Return an iterator of values (same as values())."""
64
+ ...
65
+
66
+ def values(self) -> _Iterable[T]:
67
+ """Return an iterator of values."""
68
+ ...
69
+
70
+ def entries(self) -> _Iterable[tuple[T, T]]:
71
+ """Return an iterator of [value, value] pairs."""
72
+ ...
73
+
74
+ def __iter__(self) -> _Iterable[T]:
75
+ """Iterate over values."""
76
+ ...
77
+
78
+ # ES2024 Set methods
79
+ def union(self, other: "Set[T]") -> "Set[T]":
80
+ """Return a new Set with values from both sets (ES2024)."""
81
+ ...
82
+
83
+ def intersection(self, other: "Set[T]") -> "Set[T]":
84
+ """Return a new Set with values in both sets (ES2024)."""
85
+ ...
86
+
87
+ def difference(self, other: "Set[T]") -> "Set[T]":
88
+ """Return a new Set with values in this but not other (ES2024)."""
89
+ ...
90
+
91
+ def symmetricDifference(self, other: "Set[T]") -> "Set[T]":
92
+ """Return a new Set with values in either but not both (ES2024)."""
93
+ ...
94
+
95
+ def isSubsetOf(self, other: "Set[T]") -> bool:
96
+ """Return True if all values are in other (ES2024)."""
97
+ ...
98
+
99
+ def isSupersetOf(self, other: "Set[T]") -> bool:
100
+ """Return True if all values of other are in this (ES2024)."""
101
+ ...
102
+
103
+ def isDisjointFrom(self, other: "Set[T]") -> bool:
104
+ """Return True if no values are in common (ES2024)."""
105
+ ...
106
+
107
+
108
+ # Self-register this module as a JS builtin in global scope
109
+ _register_js_module(name="Set", global_scope=True)
pulse/js/string.py ADDED
@@ -0,0 +1,35 @@
1
+ """
2
+ JavaScript String builtin module.
3
+
4
+ Usage:
5
+ import pulse.js.string as String
6
+ String.fromCharCode(65) # -> String.fromCharCode(65)
7
+ String.fromCodePoint(0x1F600) # -> String.fromCodePoint(0x1F600)
8
+
9
+ from pulse.js.string import fromCharCode, fromCodePoint
10
+ fromCharCode(65) # -> String.fromCharCode(65)
11
+ fromCodePoint(0x1F600) # -> String.fromCodePoint(0x1F600)
12
+ """
13
+
14
+ from typing import Any as _Any
15
+
16
+ from pulse.transpiler.js_module import register_js_module as _register_js_module
17
+
18
+
19
+ class String:
20
+ """JavaScript String constructor."""
21
+
22
+ def __init__(self, value: _Any) -> None: ...
23
+
24
+ @staticmethod
25
+ def fromCharCode(*codes: int) -> str: ...
26
+
27
+ @staticmethod
28
+ def fromCodePoint(*codePoints: int) -> str: ...
29
+
30
+ @staticmethod
31
+ def raw(template: str, *substitutions: str) -> str: ...
32
+
33
+
34
+ # Self-register this module as a JS builtin
35
+ _register_js_module(name="String", global_scope=True)
pulse/js/weakmap.py ADDED
@@ -0,0 +1,50 @@
1
+ """
2
+ JavaScript WeakMap builtin module.
3
+
4
+ Usage:
5
+ import pulse.js.weakmap as WeakMap
6
+ WeakMap() # -> new WeakMap()
7
+ WeakMap([[obj, "value"]]) # -> new WeakMap([[obj, "value"]])
8
+
9
+ from pulse.js.weakmap import WeakMap
10
+ WeakMap() # -> new WeakMap()
11
+ """
12
+
13
+ from collections.abc import Iterable as _Iterable
14
+ from typing import Generic as _Generic
15
+ from typing import TypeVar as _TypeVar
16
+
17
+ from pulse.transpiler.js_module import register_js_module as _register_js_module
18
+
19
+ K = _TypeVar("K") # Keys must be objects in JS, but we can't enforce that statically
20
+ V = _TypeVar("V")
21
+
22
+
23
+ class WeakMap(_Generic[K, V]):
24
+ """JavaScript WeakMap - a collection of key/value pairs with weak key references.
25
+
26
+ WeakMap[K, V] holds weak references to keys, allowing garbage collection.
27
+ Keys must be objects (not primitives).
28
+ """
29
+
30
+ def __init__(self, iterable: _Iterable[tuple[K, V]] | None = None) -> None: ...
31
+
32
+ def delete(self, key: K) -> bool:
33
+ """Remove a key and its value. Returns True if the key existed."""
34
+ ...
35
+
36
+ def get(self, key: K) -> V | None:
37
+ """Return the value for a key, or None if not present."""
38
+ ...
39
+
40
+ def has(self, key: K) -> bool:
41
+ """Return True if the key exists in the WeakMap."""
42
+ ...
43
+
44
+ def set(self, key: K, value: V) -> "WeakMap[K, V]":
45
+ """Set a key/value pair. Returns the WeakMap for chaining."""
46
+ ...
47
+
48
+
49
+ # Self-register this module as a JS builtin
50
+ _register_js_module(name="WeakMap", global_scope=True)
pulse/js/weakset.py ADDED
@@ -0,0 +1,45 @@
1
+ """
2
+ JavaScript WeakSet builtin module.
3
+
4
+ Usage:
5
+ import pulse.js.weakset as WeakSet
6
+ WeakSet() # -> new WeakSet()
7
+ WeakSet([obj1, obj2]) # -> new WeakSet([obj1, obj2])
8
+
9
+ from pulse.js.weakset import WeakSet
10
+ WeakSet() # -> new WeakSet()
11
+ """
12
+
13
+ from collections.abc import Iterable as _Iterable
14
+ from typing import Generic as _Generic
15
+ from typing import TypeVar as _TypeVar
16
+
17
+ from pulse.transpiler.js_module import register_js_module as _register_js_module
18
+
19
+ T = _TypeVar("T") # Values must be objects in JS, but we can't enforce that statically
20
+
21
+
22
+ class WeakSet(_Generic[T]):
23
+ """JavaScript WeakSet - a collection of objects with weak references.
24
+
25
+ WeakSet[T] holds weak references to values, allowing garbage collection.
26
+ Values must be objects (not primitives).
27
+ """
28
+
29
+ def __init__(self, iterable: _Iterable[T] | None = None) -> None: ...
30
+
31
+ def add(self, value: T) -> "WeakSet[T]":
32
+ """Add a value to the WeakSet. Returns the WeakSet for chaining."""
33
+ ...
34
+
35
+ def delete(self, value: T) -> bool:
36
+ """Remove a value. Returns True if the value existed."""
37
+ ...
38
+
39
+ def has(self, value: T) -> bool:
40
+ """Return True if the value exists in the WeakSet."""
41
+ ...
42
+
43
+
44
+ # Self-register this module as a JS builtin in global scope
45
+ _register_js_module(name="WeakSet", global_scope=True)