aa-coordination-resource
Dominic Gannaway 7 months ago
parent 5c0749fdf3
commit fbe0a3d350

@ -219,4 +219,4 @@ export { getContext, getAllContexts, hasContext, setContext } from './internal/c
export { hydrate, mount, unmount } from './internal/client/render.js';
export { tick, untrack } from './internal/client/runtime.js';
export { createRawSnippet } from './internal/client/dom/blocks/snippet.js';
export { Resource } from './internal/client/reactivity/resources.js';
export { Resource, getResource, deferPending } from './internal/client/reactivity/resources.js';

@ -1,12 +1,17 @@
/** @import { Derived, Effect, Source } from '#client' */
import { UNINITIALIZED } from '../../../constants.js';
import { is_array } from '../../shared/utils.js';
import { EFFECT_PRESERVED } from '../constants.js';
import { active_effect, get, handle_error } from '../runtime.js';
import { getContext, setContext } from '../context.js';
import { active_effect, get, handle_error, untrack } from '../runtime.js';
import { derived } from './deriveds.js';
import { block } from './effects.js';
import { internal_set, source } from './sources.js';
const resource_symbol = Symbol('resource');
const current_map = new WeakMap();
/**
* @template T
*/
@ -18,14 +23,28 @@ export class Resource {
/** @type {Source<boolean>} */
#pending = source(true);
/** @param {() => Promise<T>} fn */
constructor(fn) {
/**
* @param {() => Promise<T>} fn
* @param {symbol} [symbol]
*/
constructor(fn, symbol) {
let parent = /** @type {Effect | null} */ (active_effect);
current_map.set(this, this.#current);
if (parent === null) {
throw new Error('TODO cannot create resources outside of an effect');
}
if (typeof symbol === 'symbol') {
let resources = getContext(resource_symbol);
if (resources === undefined) {
resources = new Map();
setContext(resource_symbol, resources);
}
resources.set(symbol, this);
}
/** @type {{}} */
var current_token;
@ -59,39 +78,51 @@ export class Resource {
return get(this.#pending);
}
get current() {
var value = get(this.#current);
if (value === UNINITIALIZED) {
throw new Error('Resource is not yet resolved, ensure it is awaited');
}
return value;
}
get latest() {
var value = get(this.#current);
get(this.#pending);
if (value === UNINITIALIZED) {
throw new Error('Resource is not yet resolved, ensure it is awaited');
}
return value;
}
/**
* @param {(arg0: { readonly current: T; readonly pending: boolean; readonly latest: T; }) => void} onfulfilled
* @param {(arg0: { readonly current: T; readonly latest: T; }) => void} onfulfilled
* @param {((reason: any) => PromiseLike<never>) | null | undefined} onrejected
*/
then(onfulfilled, onrejected) {
return get(this.#fn).then(() => {
var self = this;
onfulfilled({
get current() { return self.current },
get pending() { return self.pending },
get latest() { return self.latest }
get current() {
return get(self.#current);
},
get latest() {
get(self.#pending);
return get(self.#current);
}
});
}, onrejected);
}
}
/**
* @template T
* @param {symbol} symbol
* @returns {Resource<T> | null}
*/
export function getResource(symbol) {
return getContext(resource_symbol)?.get(symbol) ?? null;
}
/**
* @template T
* @template V
* @param {Resource<T> | Resource<T>[]} resources
* @param {() => V} fn
*/
export function deferPending(resources, fn) {
const res = is_array(resources) ? resources : [resources];
for (let i = 0; i < res.length; i += 1) {
const resource = res[i];
const pending = untrack(() => resource.pending);
get(/** @type {Source} */ (current_map.get(resource)));
if (pending) {
break;
}
}
return untrack(fn);
}

@ -512,13 +512,19 @@ declare module 'svelte' {
* ```
* */
export function untrack<T>(fn: () => T): T;
export function isPending(fn: () => any): boolean;
export function getResource<T>(symbol: symbol): Resource<T> | null;
export function deferPending<T, V>(resources: Resource<T> | Resource<T>[], fn: () => V): V;
export class Resource<T> {
constructor(fn: () => Promise<T>);
get current(): T | Promise<Awaited<T>>;
get latest(): T | Promise<Awaited<T>>;
constructor(fn: () => Promise<T>, symbol?: symbol | undefined);
get pending(): boolean;
then(onfulfilled: (arg0: {
readonly current: T;
readonly latest: T;
}) => void, onrejected: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<void>;
#private;
}
type Getters<T> = {

Loading…
Cancel
Save