97 lines
2.7 KiB
JavaScript
97 lines
2.7 KiB
JavaScript
/**
|
|
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
|
|
*/
|
|
import { createResource, sharedConfig, untrack, catchError } from "solid-js";
|
|
import { createStore, reconcile, unwrap } from "solid-js/store";
|
|
import { isServer } from "solid-js/web";
|
|
import { setFunctionName } from "../utils.js";
|
|
export function createAsync(fn, options) {
|
|
let resource;
|
|
let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
|
|
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, options);
|
|
const resultAccessor = (() => resource());
|
|
if (options?.name)
|
|
setFunctionName(resultAccessor, options.name);
|
|
Object.defineProperty(resultAccessor, "latest", {
|
|
get() {
|
|
return resource.latest;
|
|
}
|
|
});
|
|
return resultAccessor;
|
|
}
|
|
export function createAsyncStore(fn, options = {}) {
|
|
let resource;
|
|
let prev = () => !resource || resource.state === "unresolved"
|
|
? undefined
|
|
: unwrap(resource.latest);
|
|
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, {
|
|
...options,
|
|
storage: (init) => createDeepSignal(init, options.reconcile)
|
|
});
|
|
const resultAccessor = (() => resource());
|
|
Object.defineProperty(resultAccessor, "latest", {
|
|
get() {
|
|
return resource.latest;
|
|
}
|
|
});
|
|
return resultAccessor;
|
|
}
|
|
function createDeepSignal(value, options) {
|
|
const [store, setStore] = createStore({
|
|
value: structuredClone(value)
|
|
});
|
|
return [
|
|
() => store.value,
|
|
(v) => {
|
|
typeof v === "function" && (v = v());
|
|
setStore("value", reconcile(structuredClone(v), options));
|
|
return store.value;
|
|
}
|
|
];
|
|
}
|
|
// mock promise while hydrating to prevent fetching
|
|
class MockPromise {
|
|
static all() {
|
|
return new MockPromise();
|
|
}
|
|
static allSettled() {
|
|
return new MockPromise();
|
|
}
|
|
static any() {
|
|
return new MockPromise();
|
|
}
|
|
static race() {
|
|
return new MockPromise();
|
|
}
|
|
static reject() {
|
|
return new MockPromise();
|
|
}
|
|
static resolve() {
|
|
return new MockPromise();
|
|
}
|
|
catch() {
|
|
return new MockPromise();
|
|
}
|
|
then() {
|
|
return new MockPromise();
|
|
}
|
|
finally() {
|
|
return new MockPromise();
|
|
}
|
|
}
|
|
function subFetch(fn, prev) {
|
|
if (isServer || !sharedConfig.context)
|
|
return fn(prev);
|
|
const ogFetch = fetch;
|
|
const ogPromise = Promise;
|
|
try {
|
|
window.fetch = () => new MockPromise();
|
|
Promise = MockPromise;
|
|
return fn(prev);
|
|
}
|
|
finally {
|
|
window.fetch = ogFetch;
|
|
Promise = ogPromise;
|
|
}
|
|
}
|