Skip to content

Commit 76d18f9

Browse files
committed
Rewrite event-to-object package for improved event property handling
1 parent ebd7759 commit 76d18f9

File tree

5 files changed

+51
-30
lines changed

5 files changed

+51
-30
lines changed

docs/source/about/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Unreleased
4949
- :pull:`1281` - ``reactpy.core.vdom._CustomVdomDictConstructor`` has been moved to ``reactpy.types.CustomVdomConstructor``.
5050
- :pull:`1281` - ``reactpy.core.vdom._EllipsisRepr`` has been moved to ``reactpy.types.EllipsisRepr``.
5151
- :pull:`1281` - ``reactpy.types.VdomDictConstructor`` has been renamed to ``reactpy.types.VdomConstructor``.
52+
- :pull:`1196` - Rewrite the ``event-to-object`` package to be more robust at handling properties on events.
5253

5354
**Removed**
5455

src/js/packages/@reactpy/client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"author": "Ryan Morshead",
2+
"author": "Mark Bakhit",
33
"dependencies": {
44
"json-pointer": "catalog:",
55
"preact": "catalog:",

src/js/packages/event-to-object/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"author": "Ryan Morshead",
2+
"author": "Mark Bakhit",
33
"dependencies": {
44
"json-pointer": "catalog:"
55
},
@@ -28,5 +28,5 @@
2828
"checkTypes": "tsc --noEmit"
2929
},
3030
"type": "module",
31-
"version": "0.1.2"
31+
"version": "1.0.0"
3232
}

src/js/packages/event-to-object/src/index.ts

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const maxDepthSignal = { __stop__: true };
55
*/
66
export default function convert(
77
classObject: { [key: string]: any },
8-
maxDepth: number = 10,
8+
maxDepth: number = 5,
99
): object {
1010
const visited = new WeakSet<any>();
1111
visited.add(classObject);
@@ -14,19 +14,23 @@ export default function convert(
1414
const convertedObj: { [key: string]: any } = {};
1515
for (const key in classObject) {
1616
// Skip keys that cannot be converted
17-
if (shouldIgnoreValue(classObject[key], key)) {
18-
continue;
19-
}
20-
// Handle objects (potentially cyclical)
21-
else if (typeof classObject[key] === "object") {
22-
const result = deepCloneClass(classObject[key], maxDepth, visited);
23-
if (result !== maxDepthSignal) {
24-
convertedObj[key] = result;
17+
try {
18+
if (shouldIgnoreValue(classObject[key], key)) {
19+
continue;
2520
}
26-
}
27-
// Handle simple types (non-cyclical)
28-
else {
29-
convertedObj[key] = classObject[key];
21+
// Handle objects (potentially cyclical)
22+
else if (typeof classObject[key] === "object") {
23+
const result = deepCloneClass(classObject[key], maxDepth, visited);
24+
if (result !== maxDepthSignal) {
25+
convertedObj[key] = result;
26+
}
27+
}
28+
// Handle simple types (non-cyclical)
29+
else {
30+
convertedObj[key] = classObject[key];
31+
}
32+
} catch (e) {
33+
continue;
3034
}
3135
}
3236

@@ -87,6 +91,11 @@ function deepCloneClass(
8791
return maxDepthSignal;
8892
}
8993

94+
// Safety check: WeakSet only accepts objects (and not null)
95+
if (!x || typeof x !== "object") {
96+
return x;
97+
}
98+
9099
if (visited.has(x)) {
91100
return maxDepthSignal;
92101
}
@@ -152,20 +161,24 @@ function classToObject(
152161
): object {
153162
const result: { [key: string]: any } = {};
154163
for (const key in x) {
155-
// Skip anything that should not be converted
156-
if (shouldIgnoreValue(x[key], key, x)) {
157-
continue;
158-
}
159-
// Add objects as a property if we haven't reached max depth
160-
else if (typeof x[key] === "object") {
161-
const converted = deepCloneClass(x[key], maxDepth, visited);
162-
if (converted !== maxDepthSignal) {
163-
result[key] = converted;
164+
try {
165+
// Skip anything that should not be converted
166+
if (shouldIgnoreValue(x[key], key, x)) {
167+
continue;
164168
}
165-
}
166-
// Add plain values if not skippable
167-
else {
168-
result[key] = x[key];
169+
// Add objects as a property if we haven't reached max depth
170+
else if (typeof x[key] === "object") {
171+
const converted = deepCloneClass(x[key], maxDepth, visited);
172+
if (converted !== maxDepthSignal) {
173+
result[key] = converted;
174+
}
175+
}
176+
// Add plain values if not skippable
177+
else {
178+
result[key] = x[key];
179+
}
180+
} catch (e) {
181+
continue;
169182
}
170183
}
171184

tests/conftest.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,14 @@ def install_playwright():
4242

4343
@pytest.fixture(autouse=True, scope="session")
4444
def rebuild():
45-
subprocess.run(["hatch", "build", "-t", "wheel"], check=True) # noqa: S607, S603
45+
# When running inside `hatch test`, the `HATCH_ENV_ACTIVE` environment variable
46+
# is set. If we try to run `hatch build` with this variable set, Hatch will
47+
# complain that the current environment is not a builder environment.
48+
# To fix this, we remove `HATCH_ENV_ACTIVE` from the environment variables
49+
# passed to the subprocess.
50+
env = os.environ.copy()
51+
env.pop("HATCH_ENV_ACTIVE", None)
52+
subprocess.run(["hatch", "build", "-t", "wheel"], check=True, env=env) # noqa: S607, S603
4653

4754

4855
@pytest.fixture(autouse=True, scope="function")

0 commit comments

Comments
 (0)