Skip to content

Commit 431c2cd

Browse files
committed
fix(core): canSerialize self-references
1 parent 9ae2c49 commit 431c2cd

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

packages/qwik/src/core/shared/shared-serialization.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -1523,7 +1523,7 @@ const frameworkType = (obj: any) => {
15231523
);
15241524
};
15251525

1526-
export const canSerialize = (value: any): boolean => {
1526+
export const canSerialize = (value: any, seen: WeakSet<any> = new WeakSet()): boolean => {
15271527
if (
15281528
value == null ||
15291529
typeof value === 'string' ||
@@ -1533,6 +1533,10 @@ export const canSerialize = (value: any): boolean => {
15331533
) {
15341534
return true;
15351535
} else if (typeof value === 'object') {
1536+
if (seen.has(value)) {
1537+
return true;
1538+
}
1539+
seen.add(value);
15361540
const proto = Object.getPrototypeOf(value);
15371541
if (isStore(value)) {
15381542
value = getStoreTarget(value);
@@ -1541,14 +1545,19 @@ export const canSerialize = (value: any): boolean => {
15411545
for (const key in value) {
15421546
// if the value is a props proxy, then sometimes we could create a component-level subscription,
15431547
// so we should call untrack here to avoid tracking the value
1544-
if (!canSerialize(untrack(() => value[key]))) {
1548+
if (
1549+
!canSerialize(
1550+
untrack(() => value[key]),
1551+
seen
1552+
)
1553+
) {
15451554
return false;
15461555
}
15471556
}
15481557
return true;
15491558
} else if (proto == Array.prototype) {
15501559
for (let i = 0; i < value.length; i++) {
1551-
if (!canSerialize(value[i])) {
1560+
if (!canSerialize(value[i], seen)) {
15521561
return false;
15531562
}
15541563
}

packages/qwik/src/core/shared/utils/serialize-utils.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,27 @@ import { unwrapStore } from '../../signal/store';
88

99
/** @internal */
1010
export const verifySerializable = <T>(value: T, preMessage?: string): T => {
11-
const seen = new Set();
11+
const seen = new WeakSet();
1212
return _verifySerializable(value, seen, '_', preMessage);
1313
};
1414

15-
const _verifySerializable = <T>(value: T, seen: Set<any>, ctx: string, preMessage?: string): T => {
15+
const _verifySerializable = <T>(
16+
value: T,
17+
seen: WeakSet<any>,
18+
ctx: string,
19+
preMessage?: string
20+
): T => {
1621
const unwrapped = unwrapStore(value);
1722
if (unwrapped == null) {
1823
return value;
1924
}
2025
if (shouldSerialize(unwrapped)) {
21-
if (seen.has(unwrapped)) {
22-
return value;
26+
if (typeof unwrapped === 'object') {
27+
if (seen.has(unwrapped)) {
28+
return value;
29+
}
30+
seen.add(unwrapped);
2331
}
24-
seen.add(unwrapped);
2532
if (isSignal(unwrapped)) {
2633
return value;
2734
}

0 commit comments

Comments
 (0)