Skip to content

Commit e010959

Browse files
committed
chore: move wrapped signal impl to separate file
1 parent 0f17bb3 commit e010959

File tree

13 files changed

+134
-124
lines changed

13 files changed

+134
-124
lines changed

packages/qwik/src/core/client/vnode-diff.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ import {
9191
import { mapApp_findIndx } from './util-mapArray';
9292
import { mapArray_set } from './util-mapArray';
9393
import { getNewElementNamespaceData } from './vnode-namespace';
94-
import { WrappedSignal, isSignal } from '../signal/signal';
94+
import { isSignal } from '../signal/signal';
9595
import type { Signal } from '../signal/signal.public';
9696
import { executeComponent } from '../shared/component-execution';
9797
import { isSlotProp } from '../shared/utils/prop';
@@ -102,6 +102,7 @@ import { QError, qError } from '../shared/error/error';
102102
import { getFileLocationFromJsx } from '../shared/utils/jsx-filename';
103103
import { EffectProperty } from '../signal/types';
104104
import { SubscriptionData } from '../signal/subscription-data';
105+
import { WrappedSignalImpl } from '../signal/impl/wrapped-signal-impl';
105106

106107
export const vnode_diff = (
107108
container: ClientContainer,
@@ -514,7 +515,7 @@ export const vnode_diff = (
514515
const constProps = jsxNode.constProps;
515516
if (constProps && typeof constProps == 'object' && 'name' in constProps) {
516517
const constValue = constProps.name;
517-
if (vHost && constValue instanceof WrappedSignal) {
518+
if (vHost && constValue instanceof WrappedSignalImpl) {
518519
return trackSignalAndAssignHost(constValue, vHost, EffectProperty.COMPONENT, container);
519520
}
520521
}

packages/qwik/src/core/debug.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import { isQrl } from '../server/prefetch-strategy';
22
import { isJSXNode } from './shared/jsx/jsx-runtime';
33
import { isTask } from './use/use-task';
44
import { vnode_getProp, vnode_isVNode } from './client/vnode';
5-
import { WrappedSignal, isSignal } from './signal/signal';
5+
import { isSignal } from './signal/signal';
66
import { isStore } from './signal/store';
77
import { DEBUG_TYPE } from './shared/types';
88
import { ComputedSignalImpl } from './signal/impl/computed-signal-impl';
9+
import { WrappedSignalImpl } from './signal/impl/wrapped-signal-impl';
910

1011
const stringifyPath: any[] = [];
1112
export function qwikDebugToString(value: any): any {
@@ -37,7 +38,7 @@ export function qwikDebugToString(value: any): any {
3738
return value.map(qwikDebugToString);
3839
}
3940
} else if (isSignal(value)) {
40-
if (value instanceof WrappedSignal) {
41+
if (value instanceof WrappedSignalImpl) {
4142
return 'WrappedSignal';
4243
} else if (value instanceof ComputedSignalImpl) {
4344
return 'ComputedSignal';

packages/qwik/src/core/shared/jsx/jsx-runtime.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { logOnceWarn, logWarn } from '../utils/log';
88
import { ELEMENT_ID, OnRenderProp, QScopedStyle, QSlot, QSlotS } from '../utils/markers';
99
import { qDev, seal } from '../utils/qdev';
1010
import { isArray, isObject, isString } from '../utils/types';
11-
import { WrappedSignal } from '../../signal/signal';
11+
import { WrappedSignalImpl } from '../../signal/impl/wrapped-signal-impl';
1212
import { WrappedSignalFlags } from '../../signal/types';
1313
import type { DevJSX, FunctionComponent, JSXNode, JSXNodeInternal } from './types/jsx-node';
1414
import type { QwikJSX } from './types/jsx-qwik';
@@ -346,7 +346,7 @@ class PropsProxyHandler implements ProxyHandler<any> {
346346
? this.$constProps$[prop as string]
347347
: this.$varProps$[prop as string];
348348
// a proxied value that the optimizer made
349-
return value instanceof WrappedSignal && value.$flags$ & WrappedSignalFlags.UNWRAP
349+
return value instanceof WrappedSignalImpl && value.$flags$ & WrappedSignalFlags.UNWRAP
350350
? value.value
351351
: value;
352352
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { WrappedSignal } from '../../signal/signal';
1+
import { WrappedSignalImpl } from '../../signal/impl/wrapped-signal-impl';
22

33
/** @internal */
44
export const _fnSignal = <T extends (...args: any) => any>(
55
fn: T,
66
args: Parameters<T>,
77
fnStr?: string
88
) => {
9-
return new WrappedSignal(null, fn, args, fnStr || null);
9+
return new WrappedSignalImpl(null, fn, args, fnStr || null);
1010
};

packages/qwik/src/core/shared/scheduler.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ import {
9191
} from '../client/types';
9292
import { VNodeJournalOpCode, vnode_isVNode, vnode_setAttr } from '../client/vnode';
9393
import { vnode_diff } from '../client/vnode-diff';
94-
import { triggerEffects, type WrappedSignal } from '../signal/signal';
94+
import { triggerEffects } from '../signal/signal';
9595
import { isSignal, type Signal } from '../signal/signal.public';
9696
import type { TargetType } from '../signal/store';
9797
import type { ISsrNode } from '../ssr/ssr-types';
@@ -121,6 +121,7 @@ import { serializeAttribute } from './utils/styles';
121121
import type { ValueOrPromise } from './utils/types';
122122
import type { NodePropPayload } from '../signal/subscription-data';
123123
import type { ComputedSignalImpl } from '../signal/impl/computed-signal-impl';
124+
import type { WrappedSignalImpl } from '../signal/impl/wrapped-signal-impl';
124125

125126
// Turn this on to get debug output of what the scheduler is doing.
126127
const DEBUG: boolean = false;
@@ -462,7 +463,9 @@ export const createScheduler = (
462463
}
463464
case ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS: {
464465
{
465-
const target = chore.$target$ as ComputedSignalImpl<unknown> | WrappedSignal<unknown>;
466+
const target = chore.$target$ as
467+
| ComputedSignalImpl<unknown>
468+
| WrappedSignalImpl<unknown>;
466469
const forceRunEffects = target.$forceRunEffects$;
467470
target.$forceRunEffects$ = false;
468471
if (!target.$effects$?.size) {

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

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,7 @@ import { type DomContainer } from '../client/dom-container';
88
import type { VNode } from '../client/types';
99
import { vnode_getNode, vnode_isVNode, vnode_locate, vnode_toString } from '../client/vnode';
1010
import { _EFFECT_BACK_REF, NEEDS_COMPUTATION } from '../signal/flags';
11-
import {
12-
SerializerSignalImpl,
13-
WrappedSignal,
14-
isSerializerObj,
15-
type SerializerArg,
16-
} from '../signal/signal';
11+
import { SerializerSignalImpl, isSerializerObj, type SerializerArg } from '../signal/signal';
1712
import {
1813
getOrCreateStore,
1914
getStoreHandler,
@@ -59,6 +54,7 @@ import {
5954
import { SubscriptionData, type NodePropData } from '../signal/subscription-data';
6055
import { SignalImpl } from '../signal/impl/signal-impl';
6156
import { ComputedSignalImpl } from '../signal/impl/computed-signal-impl';
57+
import { WrappedSignalImpl } from '../signal/impl/wrapped-signal-impl';
6258

6359
const deserializedProxyMap = new WeakMap<object, unknown[]>();
6460

@@ -271,7 +267,7 @@ const inflate = (
271267
break;
272268
}
273269
case TypeIds.WrappedSignal: {
274-
const signal = target as WrappedSignal<unknown>;
270+
const signal = target as WrappedSignalImpl<unknown>;
275271
const d = data as [
276272
number,
277273
unknown[],
@@ -491,7 +487,7 @@ const allocate = (container: DeserializeContainer, typeId: number, value: unknow
491487
case TypeIds.Signal:
492488
return new SignalImpl(container as any, 0);
493489
case TypeIds.WrappedSignal:
494-
return new WrappedSignal(container as any, null!, null!, null!);
490+
return new WrappedSignalImpl(container as any, null!, null!, null!);
495491
case TypeIds.ComputedSignal:
496492
return new ComputedSignalImpl(container as any, null!);
497493
case TypeIds.SerializerSignal:
@@ -876,7 +872,7 @@ export const createSerializationContext = (
876872
discoveredValues.push(obj.$effects$);
877873
}
878874
// WrappedSignal uses syncQrl which has no captured refs
879-
if (obj instanceof WrappedSignal) {
875+
if (obj instanceof WrappedSignalImpl) {
880876
discoverEffectBackRefs(obj[_EFFECT_BACK_REF], discoveredValues);
881877
if (obj.$args$) {
882878
discoveredValues.push(...obj.$args$);
@@ -1235,7 +1231,7 @@ function serialize(serializationContext: SerializationContext): void {
12351231
? NEEDS_COMPUTATION
12361232
: value.$untrackedValue$;
12371233

1238-
if (value instanceof WrappedSignal) {
1234+
if (value instanceof WrappedSignalImpl) {
12391235
output(TypeIds.WrappedSignal, [
12401236
...serializeWrappingFn(serializationContext, value),
12411237
filterEffectBackRefs(value[_EFFECT_BACK_REF]),
@@ -1380,7 +1376,7 @@ function filterEffectBackRefs(effectBackRef: Map<string, EffectSubscription> | n
13801376

13811377
function serializeWrappingFn(
13821378
serializationContext: SerializationContext,
1383-
value: WrappedSignal<any>
1379+
value: WrappedSignalImpl<any>
13841380
) {
13851381
// if value is an object then we need to wrap this in ()
13861382
if (value.$funcStr$ && value.$funcStr$[0] === '{') {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { assertFalse } from '../../shared/error/assert';
2+
import { QError, qError } from '../../shared/error/error';
3+
import type { Container, HostElement } from '../../shared/types';
4+
import { ChoreType } from '../../shared/util-chore-type';
5+
import { trackSignal } from '../../use/use-core';
6+
import { _EFFECT_BACK_REF, NEEDS_COMPUTATION } from '../flags';
7+
import { triggerEffects } from '../signal';
8+
import type { BackRef } from '../signal-cleanup';
9+
import type { AllSignalFlags, EffectSubscription } from '../types';
10+
import { EffectProperty, SignalFlags, WrappedSignalFlags } from '../types';
11+
import { SignalImpl } from './signal-impl';
12+
13+
export class WrappedSignalImpl<T> extends SignalImpl<T> implements BackRef {
14+
$args$: any[];
15+
$func$: (...args: any[]) => T;
16+
$funcStr$: string | null;
17+
18+
$flags$: AllSignalFlags;
19+
$hostElement$: HostElement | null = null;
20+
$forceRunEffects$: boolean = false;
21+
[_EFFECT_BACK_REF]: Map<EffectProperty | string, EffectSubscription> | null = null;
22+
23+
constructor(
24+
container: Container | null,
25+
fn: (...args: any[]) => T,
26+
args: any[],
27+
fnStr: string | null,
28+
// We need a separate flag to know when the computation needs running because
29+
// we need the old value to know if effects need running after computation
30+
flags: SignalFlags = SignalFlags.INVALID | WrappedSignalFlags.UNWRAP
31+
) {
32+
super(container, NEEDS_COMPUTATION);
33+
this.$args$ = args;
34+
this.$func$ = fn;
35+
this.$funcStr$ = fnStr;
36+
this.$flags$ = flags;
37+
}
38+
39+
$invalidate$() {
40+
this.$flags$ |= SignalFlags.INVALID;
41+
this.$forceRunEffects$ = false;
42+
// We should only call subscribers if the calculation actually changed.
43+
// Therefore, we need to calculate the value now.
44+
this.$container$?.$scheduler$(
45+
ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
46+
this.$hostElement$,
47+
this
48+
);
49+
}
50+
51+
/**
52+
* Use this to force running subscribers, for example when the calculated value has mutated but
53+
* remained the same object.
54+
*/
55+
force() {
56+
this.$flags$ |= SignalFlags.INVALID;
57+
this.$forceRunEffects$ = false;
58+
triggerEffects(this.$container$, this, this.$effects$);
59+
}
60+
61+
get untrackedValue() {
62+
const didChange = this.$computeIfNeeded$();
63+
if (didChange) {
64+
this.$forceRunEffects$ = didChange;
65+
}
66+
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
67+
return this.$untrackedValue$;
68+
}
69+
70+
$computeIfNeeded$() {
71+
if (!(this.$flags$ & SignalFlags.INVALID)) {
72+
return false;
73+
}
74+
const untrackedValue = trackSignal(
75+
() => this.$func$(...this.$args$),
76+
this,
77+
EffectProperty.VNODE,
78+
this.$container$!
79+
);
80+
// TODO: we should remove invalid flag here
81+
// this.$flags$ &= ~SignalFlags.INVALID;
82+
const didChange = untrackedValue !== this.$untrackedValue$;
83+
if (didChange) {
84+
this.$untrackedValue$ = untrackedValue;
85+
}
86+
return didChange;
87+
}
88+
// Make this signal read-only
89+
set value(_: any) {
90+
throw qError(QError.wrappedReadOnly);
91+
}
92+
// Getters don't get inherited when overriding a setter
93+
get value() {
94+
return super.value;
95+
}
96+
}

packages/qwik/src/core/signal/signal-cleanup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { WrappedSignal } from './signal';
21
import { StoreHandler, getStoreHandler } from './store';
32
import type { Container } from '../shared/types';
43
import { ensureMaterialized, vnode_isElementVNode, vnode_isVNode } from '../client/vnode';
@@ -10,6 +9,7 @@ import {
109
type EffectSubscription,
1110
} from './types';
1211
import { SignalImpl } from './impl/signal-impl';
12+
import { WrappedSignalImpl } from './impl/wrapped-signal-impl';
1313

1414
/** Class for back reference to the EffectSubscription */
1515
export abstract class BackRef {
@@ -47,7 +47,7 @@ function clearSignal(container: Container, producer: SignalImpl, effect: EffectS
4747
effects.delete(effect);
4848
}
4949

50-
if (producer instanceof WrappedSignal) {
50+
if (producer instanceof WrappedSignalImpl) {
5151
producer.$hostElement$ = null;
5252
clearAllEffects(container, producer);
5353
}

packages/qwik/src/core/signal/signal-utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { _CONST_PROPS, _IMMUTABLE } from '../shared/utils/constants';
22
import { assertEqual } from '../shared/error/assert';
33
import { isObject } from '../shared/utils/types';
4-
import { WrappedSignal } from './signal';
54
import { isSignal, type Signal } from './signal.public';
65
import { getStoreTarget } from './store';
76
import { isPropsProxy } from '../shared/jsx/jsx-runtime';
87
import { SignalFlags, WrappedSignalFlags } from './types';
8+
import { WrappedSignalImpl } from './impl/wrapped-signal-impl';
99

1010
// Keep these properties named like this so they're the same as from wrapSignal
1111
const getValueProp = (p0: any) => p0.value;
1212
const getProp = (p0: any, p1: string) => p0[p1];
1313

1414
const getWrapped = (args: any[]) =>
15-
new WrappedSignal(null, args.length === 1 ? getValueProp : getProp, args, null);
15+
new WrappedSignalImpl(null, args.length === 1 ? getValueProp : getProp, args, null);
1616

1717
/**
1818
* This wraps a property access of a possible Signal/Store into a WrappedSignal. The optimizer does
@@ -34,7 +34,7 @@ export const _wrapProp = <T extends Record<any, any>, P extends keyof T>(...args
3434
}
3535
if (isSignal(obj)) {
3636
assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
37-
if (obj instanceof WrappedSignal && obj.flags & WrappedSignalFlags.UNWRAP) {
37+
if (obj instanceof WrappedSignalImpl && obj.flags & WrappedSignalFlags.UNWRAP) {
3838
return obj;
3939
}
4040
return getWrapped(args);
@@ -70,7 +70,7 @@ export const _wrapStore = <T extends Record<any, any>, P extends keyof T>(
7070
if (isSignal(value)) {
7171
return value;
7272
} else {
73-
return new WrappedSignal(null, getProp, [obj, prop], null, SignalFlags.INVALID);
73+
return new WrappedSignalImpl(null, getProp, [obj, prop], null, SignalFlags.INVALID);
7474
}
7575
};
7676

0 commit comments

Comments
 (0)