pull/15579/head
Rich Harris 1 year ago
parent 36bfef986a
commit 96e5edc6fd

@ -28,47 +28,35 @@ function identity(fn) {
return fn;
}
/**
* @param {ValueOptions | undefined} options
* @returns {ValueOptions | undefined}
*/
function clone_options(options) {
return options != null
? {
onchange: options.onchange
}
: undefined;
}
/** @type {ProxyMetadata | null} */
var parent_metadata = null;
/**
* @template T
* @param {T} value
* @param {ValueOptions} [_options]
* @param {ValueOptions} [options]
* @param {Source<T>} [prev] dev mode only
* @returns {T}
*/
export function proxy(value, _options, prev) {
export function proxy(value, options, prev) {
// if non-proxyable, or is already a proxy, return `value`
if (typeof value !== 'object' || value === null) {
return value;
}
var options = clone_options(_options);
var onchange = options?.onchange;
if (STATE_SYMBOL in value) {
// @ts-ignore
value[PROXY_ONCHANGE_SYMBOL](options?.onchange);
value[PROXY_ONCHANGE_SYMBOL](onchange);
return value;
}
if (options?.onchange) {
if (onchange) {
// if there's an onchange we actually store that but override the value
// to store every other onchange that new proxies might add
var onchanges = new Set([options.onchange]);
options.onchange = () => {
var onchanges = new Set([onchange]);
onchange = () => {
for (let onchange of onchanges) {
onchange();
}
@ -118,7 +106,7 @@ export function proxy(value, _options, prev) {
// mutations to the array are properly synced with our proxy
sources.set(
'length',
source(/** @type {any[]} */ (value).length, clone_options(options), stack)
source(/** @type {any[]} */ (value).length, onchange && { onchange }, stack)
);
}
@ -165,7 +153,7 @@ export function proxy(value, _options, prev) {
var s = sources.get(prop);
if (s === undefined) {
s = with_parent(() => source(descriptor.value, clone_options(options), stack));
s = with_parent(() => source(descriptor.value, onchange && { onchange }, stack));
sources.set(prop, s);
} else {
set(
@ -184,7 +172,7 @@ export function proxy(value, _options, prev) {
if (prop in target) {
sources.set(
prop,
with_parent(() => source(UNINITIALIZED, clone_options(options), stack))
with_parent(() => source(UNINITIALIZED, onchange && { onchange }, stack))
);
}
} else {
@ -201,7 +189,7 @@ export function proxy(value, _options, prev) {
// when we delete a property if the source is a proxy we remove the current onchange from
// the proxy `onchanges` so that it doesn't trigger it anymore
if (typeof s.v === 'object' && s.v !== null && STATE_SYMBOL in s.v) {
s.v[PROXY_ONCHANGE_SYMBOL](options?.onchange, true);
s.v[PROXY_ONCHANGE_SYMBOL](onchange, true);
}
set(s, UNINITIALIZED);
update_version(version);
@ -227,14 +215,12 @@ export function proxy(value, _options, prev) {
// we either add or remove the passed in value
// to the onchanges array or we set every source onchange
// to the passed in value (if it's undefined it will make the chain stop)
if (options?.onchange != null && value && !remove) {
if (onchange != null && value && !remove) {
onchanges?.add?.(value);
} else if (options?.onchange != null && value) {
} else if (onchange != null && value) {
onchanges?.delete?.(value);
} else {
options = {
onchange: value
};
onchange = value;
for (let [, s] of sources) {
if (s.o) {
s.o.onchange = value;
@ -249,7 +235,7 @@ export function proxy(value, _options, prev) {
// create a source, but only if it's an own property and not a prototype property
if (s === undefined && (!exists || get_descriptor(target, prop)?.writable)) {
let opt = clone_options(options);
let opt = onchange && { onchange };
s = with_parent(() =>
source(proxy(exists ? target[prop] : UNINITIALIZED, opt), opt, stack)
);
@ -281,7 +267,7 @@ export function proxy(value, _options, prev) {
if (
is_proxied_array &&
options?.onchange != null &&
onchange != null &&
array_methods.includes(/** @type {string} */ (prop))
) {
return batch_onchange(v);
@ -330,7 +316,7 @@ export function proxy(value, _options, prev) {
(active_effect !== null && (!has || get_descriptor(target, prop)?.writable))
) {
if (s === undefined) {
let opt = clone_options(options);
let opt = onchange && { onchange };
s = with_parent(() => source(has ? proxy(target[prop], opt) : UNINITIALIZED, opt, stack));
sources.set(prop, s);
}
@ -362,14 +348,14 @@ export function proxy(value, _options, prev) {
other_s.v !== null &&
STATE_SYMBOL in other_s.v
) {
other_s.v[PROXY_ONCHANGE_SYMBOL](options?.onchange, true);
other_s.v[PROXY_ONCHANGE_SYMBOL](onchange, true);
}
set(other_s, UNINITIALIZED);
} else if (i in target) {
// If the item exists in the original, we need to create a uninitialized source,
// else a later read of the property would result in a source being created with
// the value of the original item at that index.
other_s = with_parent(() => source(UNINITIALIZED, clone_options(options), stack));
other_s = with_parent(() => source(UNINITIALIZED, onchange && { onchange }, stack));
sources.set(i + '', other_s);
}
}
@ -381,7 +367,7 @@ export function proxy(value, _options, prev) {
// object property before writing to that property.
if (s === undefined) {
if (!has || get_descriptor(target, prop)?.writable) {
const opt = clone_options(options);
const opt = onchange && { onchange };
s = with_parent(() => source(undefined, opt, stack));
set(
s,
@ -394,11 +380,11 @@ export function proxy(value, _options, prev) {
// when we set a property if the source is a proxy we remove the current onchange from
// the proxy `onchanges` so that it doesn't trigger it anymore
if (typeof s.v === 'object' && s.v !== null && STATE_SYMBOL in s.v) {
s.v[PROXY_ONCHANGE_SYMBOL](options?.onchange, true);
s.v[PROXY_ONCHANGE_SYMBOL](onchange, true);
}
set(
s,
with_parent(() => proxy(value, clone_options(options)))
with_parent(() => proxy(value, onchange && { onchange }))
);
}
})();

Loading…
Cancel
Save