All files / src/internal/client/reactivity store.js

100% Statements 153/153
100% Branches 19/19
100% Functions 8/8
100% Lines 148/148

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 1492x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1095x 1095x 1095x 1095x 1095x 1095x 1095x 367x 367x 367x 367x 10x 10x 367x 357x 357x 357x 669x 357x 357x 357x 669x 312x 312x 357x 357x 357x 357x 367x 1095x 1095x 1095x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 22x 22x 22x 22x 14x 14x 14x 14x 22x 22x 22x 2x 2x 2x 2x 2x 2x 2x 2x 2x 112x 112x 112x 2x 2x 2x 2x 2x 2x 8x 8x 8x 8x 8x 2x 2x 2x 2x 2x 2x 215x 215x 215x 215x 215x 315x 315x 315x 215x 215x 215x 215x 2x 2x 2x 2x 2x 2x 2x 2x 2x 50x 50x 50x 2x 2x 2x 2x 2x 2x 2x 2x 34x 34x 34x 2x 2x 2x 2x 2x 2x 2x 2x 4x 4x 4x 4x  
/** @import { StoreReferencesContainer } from '#client' */
/** @import { Store } from '#shared' */
import { subscribe_to_store } from '../../../store/utils.js';
import { noop } from '../../shared/utils.js';
import { get } from '../runtime.js';
import { teardown } from './effects.js';
import { mutable_source, set } from './sources.js';
 
/**
 * Gets the current value of a store. If the store isn't subscribed to yet, it will create a proxy
 * signal that will be updated when the store is. The store references container is needed to
 * track reassignments to stores and to track the correct component context.
 * @template V
 * @param {Store<V> | null | undefined} store
 * @param {string} store_name
 * @param {StoreReferencesContainer} stores
 * @returns {V}
 */
export function store_get(store, store_name, stores) {
	const entry = (stores[store_name] ??= {
		store: null,
		source: mutable_source(undefined),
		unsubscribe: noop
	});
 
	if (entry.store !== store) {
		entry.unsubscribe();
		entry.store = store ?? null;
 
		if (store == null) {
			entry.source.v = undefined; // see synchronous callback comment below
			entry.unsubscribe = noop;
		} else {
			var is_synchronous_callback = true;
 
			entry.unsubscribe = subscribe_to_store(store, (v) => {
				if (is_synchronous_callback) {
					// If the first updates to the store value (possibly multiple of them) are synchronously
					// inside a derived, we will hit the `state_unsafe_mutation` error if we `set` the value
					entry.source.v = v;
				} else {
					set(entry.source, v);
				}
			});
 
			is_synchronous_callback = false;
		}
	}
 
	return get(entry.source);
}
 
/**
 * Unsubscribe from a store if it's not the same as the one in the store references container.
 * We need this in addition to `store_get` because someone could unsubscribe from a store but
 * then never subscribe to the new one (if any), causing the subscription to stay open wrongfully.
 * @param {Store<any> | null | undefined} store
 * @param {string} store_name
 * @param {StoreReferencesContainer} stores
 */
export function store_unsub(store, store_name, stores) {
	/** @type {StoreReferencesContainer[''] | undefined} */
	let entry = stores[store_name];
 
	if (entry && entry.store !== store) {
		// Don't reset store yet, so that store_get above can resubscribe to new store if necessary
		entry.unsubscribe();
		entry.unsubscribe = noop;
	}
 
	return store;
}
 
/**
 * Sets the new value of a store and returns that value.
 * @template V
 * @param {Store<V>} store
 * @param {V} value
 * @returns {V}
 */
export function store_set(store, value) {
	store.set(value);
	return value;
}
 
/**
 * @param {StoreReferencesContainer} stores
 * @param {string} store_name
 */
export function invalidate_store(stores, store_name) {
	var entry = stores[store_name];
	if (entry.store !== null) {
		store_set(entry.store, entry.source.v);
	}
}
 
/**
 * Unsubscribes from all auto-subscribed stores on destroy
 * @returns {StoreReferencesContainer}
 */
export function setup_stores() {
	/** @type {StoreReferencesContainer} */
	const stores = {};
 
	teardown(() => {
		for (var store_name in stores) {
			const ref = stores[store_name];
			ref.unsubscribe();
		}
	});
 
	return stores;
}
 
/**
 * Updates a store with a new value.
 * @param {Store<V>} store  the store to update
 * @param {any} expression  the expression that mutates the store
 * @param {V} new_value  the new store value
 * @template V
 */
export function store_mutate(store, expression, new_value) {
	store.set(new_value);
	return expression;
}
 
/**
 * @param {Store<number>} store
 * @param {number} store_value
 * @param {1 | -1} [d]
 * @returns {number}
 */
export function update_store(store, store_value, d = 1) {
	store.set(store_value + d);
	return store_value;
}
 
/**
 * @param {Store<number>} store
 * @param {number} store_value
 * @param {1 | -1} [d]
 * @returns {number}
 */
export function update_pre_store(store, store_value, d = 1) {
	const value = store_value + d;
	store.set(value);
	return value;
}