@solidjs/router 0.16.0 → 0.17.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +85 -79
  2. package/dist/components.jsx +22 -16
  3. package/dist/data/action.d.ts +12 -10
  4. package/dist/data/action.js +98 -78
  5. package/dist/data/events.d.ts +8 -1
  6. package/dist/data/events.js +3 -3
  7. package/dist/data/index.d.ts +2 -3
  8. package/dist/data/index.js +2 -3
  9. package/dist/data/query.d.ts +1 -3
  10. package/dist/data/query.js +10 -16
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +212 -261
  13. package/dist/index.jsx +1 -1
  14. package/dist/lifecycle.js +1 -1
  15. package/dist/routers/HashRouter.js +1 -1
  16. package/dist/routers/MemoryRouter.js +1 -1
  17. package/dist/routers/Router.js +2 -2
  18. package/dist/routers/StaticRouter.js +1 -1
  19. package/dist/routers/components.d.ts +0 -4
  20. package/dist/routers/components.jsx +30 -19
  21. package/dist/routing.d.ts +4 -3
  22. package/dist/routing.js +71 -49
  23. package/dist/types.d.ts +3 -18
  24. package/dist/utils.d.ts +1 -0
  25. package/dist/utils.js +8 -0
  26. package/package.json +8 -6
  27. package/dist/data/createAsync.d.ts +0 -32
  28. package/dist/data/createAsync.js +0 -93
  29. package/dist/src/components.d.ts +0 -31
  30. package/dist/src/components.jsx +0 -39
  31. package/dist/src/data/action.d.ts +0 -17
  32. package/dist/src/data/action.js +0 -163
  33. package/dist/src/data/action.spec.d.ts +0 -1
  34. package/dist/src/data/action.spec.js +0 -297
  35. package/dist/src/data/createAsync.d.ts +0 -32
  36. package/dist/src/data/createAsync.js +0 -96
  37. package/dist/src/data/createAsync.spec.d.ts +0 -1
  38. package/dist/src/data/createAsync.spec.js +0 -196
  39. package/dist/src/data/events.d.ts +0 -9
  40. package/dist/src/data/events.js +0 -123
  41. package/dist/src/data/events.spec.d.ts +0 -1
  42. package/dist/src/data/events.spec.js +0 -567
  43. package/dist/src/data/index.d.ts +0 -4
  44. package/dist/src/data/index.js +0 -4
  45. package/dist/src/data/query.d.ts +0 -23
  46. package/dist/src/data/query.js +0 -232
  47. package/dist/src/data/query.spec.d.ts +0 -1
  48. package/dist/src/data/query.spec.js +0 -354
  49. package/dist/src/data/response.d.ts +0 -4
  50. package/dist/src/data/response.js +0 -42
  51. package/dist/src/data/response.spec.d.ts +0 -1
  52. package/dist/src/data/response.spec.js +0 -165
  53. package/dist/src/index.d.ts +0 -7
  54. package/dist/src/index.jsx +0 -6
  55. package/dist/src/lifecycle.d.ts +0 -5
  56. package/dist/src/lifecycle.js +0 -69
  57. package/dist/src/routers/HashRouter.d.ts +0 -9
  58. package/dist/src/routers/HashRouter.js +0 -41
  59. package/dist/src/routers/MemoryRouter.d.ts +0 -24
  60. package/dist/src/routers/MemoryRouter.js +0 -57
  61. package/dist/src/routers/Router.d.ts +0 -9
  62. package/dist/src/routers/Router.js +0 -45
  63. package/dist/src/routers/StaticRouter.d.ts +0 -6
  64. package/dist/src/routers/StaticRouter.js +0 -15
  65. package/dist/src/routers/components.d.ts +0 -27
  66. package/dist/src/routers/components.jsx +0 -118
  67. package/dist/src/routers/createRouter.d.ts +0 -10
  68. package/dist/src/routers/createRouter.js +0 -41
  69. package/dist/src/routers/index.d.ts +0 -11
  70. package/dist/src/routers/index.js +0 -6
  71. package/dist/src/routing.d.ts +0 -175
  72. package/dist/src/routing.js +0 -560
  73. package/dist/src/types.d.ts +0 -200
  74. package/dist/src/types.js +0 -1
  75. package/dist/src/utils.d.ts +0 -13
  76. package/dist/src/utils.js +0 -185
  77. package/dist/test/helpers.d.ts +0 -6
  78. package/dist/test/helpers.js +0 -50
@@ -1,31 +0,0 @@
1
- import type { JSX } from "solid-js";
2
- import type { Location, Navigator } from "./types.js";
3
- declare module "solid-js" {
4
- namespace JSX {
5
- interface AnchorHTMLAttributes<T> {
6
- state?: string;
7
- noScroll?: boolean;
8
- replace?: boolean;
9
- preload?: boolean;
10
- link?: boolean;
11
- }
12
- }
13
- }
14
- export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
15
- href: string;
16
- replace?: boolean | undefined;
17
- noScroll?: boolean | undefined;
18
- state?: unknown | undefined;
19
- inactiveClass?: string | undefined;
20
- activeClass?: string | undefined;
21
- end?: boolean | undefined;
22
- }
23
- export declare function A(props: AnchorProps): JSX.Element;
24
- export interface NavigateProps {
25
- href: ((args: {
26
- navigate: Navigator;
27
- location: Location;
28
- }) => string) | string;
29
- state?: unknown;
30
- }
31
- export declare function Navigate(props: NavigateProps): null;
@@ -1,39 +0,0 @@
1
- import { createMemo, mergeProps, splitProps } from "solid-js";
2
- import { useHref, useLocation, useNavigate, useResolvedPath } from "./routing.js";
3
- import { normalizePath } from "./utils.js";
4
- export function A(props) {
5
- props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
6
- const [, rest] = splitProps(props, [
7
- "href",
8
- "state",
9
- "class",
10
- "activeClass",
11
- "inactiveClass",
12
- "end"
13
- ]);
14
- const to = useResolvedPath(() => props.href);
15
- const href = useHref(to);
16
- const location = useLocation();
17
- const isActive = createMemo(() => {
18
- const to_ = to();
19
- if (to_ === undefined)
20
- return [false, false];
21
- const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase();
22
- const loc = decodeURI(normalizePath(location.pathname).toLowerCase());
23
- return [props.end ? path === loc : loc.startsWith(path + "/") || loc === path, path === loc];
24
- });
25
- return (<a {...rest} href={href() || props.href} state={JSON.stringify(props.state)} classList={{
26
- ...(props.class && { [props.class]: true }),
27
- [props.inactiveClass]: !isActive()[0],
28
- [props.activeClass]: isActive()[0],
29
- ...rest.classList
30
- }} link aria-current={isActive()[1] ? "page" : undefined}/>);
31
- }
32
- export function Navigate(props) {
33
- const navigate = useNavigate();
34
- const location = useLocation();
35
- const { href, state } = props;
36
- const path = typeof href === "function" ? href({ navigate, location }) : href;
37
- navigate(path, { replace: true, state });
38
- return null;
39
- }
@@ -1,17 +0,0 @@
1
- import { JSX } from "solid-js";
2
- import type { Submission, SubmissionStub, NarrowResponse } from "../types.js";
3
- export type Action<T extends Array<any>, U, V = T> = (T extends [FormData | URLSearchParams] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<NarrowResponse<U>>) & {
4
- url: string;
5
- with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<NarrowResponse<U>>, ...args: A): Action<B, U, V>;
6
- };
7
- export declare const actions: Map<string, Action<any, any, any>>;
8
- export declare function useSubmissions<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>>[] & {
9
- pending: boolean;
10
- };
11
- export declare function useSubmission<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>> | SubmissionStub;
12
- export declare function useAction<T extends Array<any>, U, V>(action: Action<T, U, V>): (...args: Parameters<Action<T, U, V>>) => Promise<NarrowResponse<U>>;
13
- export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>;
14
- export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, options?: {
15
- name?: string;
16
- onComplete?: (s: Submission<T, U>) => void;
17
- }): Action<T, U>;
@@ -1,163 +0,0 @@
1
- import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
2
- import { isServer } from "solid-js/web";
3
- import { useRouter } from "../routing.js";
4
- import { mockBase, setFunctionName } from "../utils.js";
5
- import { cacheKeyOp, hashKey, revalidate, query } from "./query.js";
6
- export const actions = /* #__PURE__ */ new Map();
7
- export function useSubmissions(fn, filter) {
8
- const router = useRouter();
9
- const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.base && (!filter || filter(s.input))));
10
- return new Proxy([], {
11
- get(_, property) {
12
- if (property === $TRACK)
13
- return subs();
14
- if (property === "pending")
15
- return subs().some(sub => !sub.result);
16
- return subs()[property];
17
- },
18
- has(_, property) {
19
- return property in subs();
20
- }
21
- });
22
- }
23
- export function useSubmission(fn, filter) {
24
- const submissions = useSubmissions(fn, filter);
25
- return new Proxy({}, {
26
- get(_, property) {
27
- if ((submissions.length === 0 && property === "clear") || property === "retry")
28
- return () => { };
29
- return submissions[submissions.length - 1]?.[property];
30
- }
31
- });
32
- }
33
- export function useAction(action) {
34
- const r = useRouter();
35
- return (...args) => action.apply({ r }, args);
36
- }
37
- export function action(fn, options = {}) {
38
- function mutate(...variables) {
39
- const router = this.r;
40
- const form = this.f;
41
- const p = (router.singleFlight && fn.withOptions
42
- ? fn.withOptions({ headers: { "X-Single-Flight": "true" } })
43
- : fn)(...variables);
44
- const [result, setResult] = createSignal();
45
- let submission;
46
- function handler(error) {
47
- return async (res) => {
48
- const result = await handleResponse(res, error, router.navigatorFactory());
49
- let retry = null;
50
- o.onComplete?.({
51
- ...submission,
52
- result: result?.data,
53
- error: result?.error,
54
- pending: false,
55
- retry() {
56
- return (retry = submission.retry());
57
- }
58
- });
59
- if (retry)
60
- return retry;
61
- if (!result)
62
- return submission.clear();
63
- setResult(result);
64
- if (result.error && !form)
65
- throw result.error;
66
- return result.data;
67
- };
68
- }
69
- router.submissions[1](s => [
70
- ...s,
71
- (submission = {
72
- input: variables,
73
- url,
74
- get result() {
75
- return result()?.data;
76
- },
77
- get error() {
78
- return result()?.error;
79
- },
80
- get pending() {
81
- return !result();
82
- },
83
- clear() {
84
- router.submissions[1](v => v.filter(i => i !== submission));
85
- },
86
- retry() {
87
- setResult(undefined);
88
- const p = fn(...variables);
89
- return p.then(handler(), handler(true));
90
- }
91
- })
92
- ]);
93
- return p.then(handler(), handler(true));
94
- }
95
- const o = typeof options === "string" ? { name: options } : options;
96
- const name = o.name || (!isServer ? String(hashString(fn.toString())) : undefined);
97
- const url = fn.url || (name && `https://action/${name}`) || "";
98
- mutate.base = url;
99
- if (name)
100
- setFunctionName(mutate, name);
101
- return toAction(mutate, url);
102
- }
103
- function toAction(fn, url) {
104
- fn.toString = () => {
105
- if (!url)
106
- throw new Error("Client Actions need explicit names if server rendered");
107
- return url;
108
- };
109
- fn.with = function (...args) {
110
- const newFn = function (...passedArgs) {
111
- return fn.call(this, ...args, ...passedArgs);
112
- };
113
- newFn.base = fn.base;
114
- const uri = new URL(url, mockBase);
115
- uri.searchParams.set("args", hashKey(args));
116
- return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
117
- };
118
- fn.url = url;
119
- if (!isServer) {
120
- actions.set(url, fn);
121
- getOwner() && onCleanup(() => actions.delete(url));
122
- }
123
- return fn;
124
- }
125
- const hashString = (s) => s.split("").reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0);
126
- async function handleResponse(response, error, navigate) {
127
- let data;
128
- let custom;
129
- let keys;
130
- let flightKeys;
131
- if (response instanceof Response) {
132
- if (response.headers.has("X-Revalidate"))
133
- keys = response.headers.get("X-Revalidate").split(",");
134
- if (response.customBody) {
135
- data = custom = await response.customBody();
136
- if (response.headers.has("X-Single-Flight")) {
137
- data = data._$value;
138
- delete custom._$value;
139
- flightKeys = Object.keys(custom);
140
- }
141
- }
142
- if (response.headers.has("Location")) {
143
- const locationUrl = response.headers.get("Location") || "/";
144
- if (locationUrl.startsWith("http")) {
145
- window.location.href = locationUrl;
146
- }
147
- else {
148
- navigate(locationUrl);
149
- }
150
- }
151
- }
152
- else if (error)
153
- return { error: response };
154
- else
155
- data = response;
156
- // invalidate
157
- cacheKeyOp(keys, entry => (entry[0] = 0));
158
- // set cache
159
- flightKeys && flightKeys.forEach(k => query.set(k, custom[k]));
160
- // trigger revalidation
161
- await revalidate(keys, false);
162
- return data != null ? { data } : undefined;
163
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,297 +0,0 @@
1
- import { createRoot } from "solid-js";
2
- import { vi } from "vitest";
3
- import { action, useAction, useSubmission, useSubmissions, actions } from "./action.js";
4
- import { createMockRouter } from "../../test/helpers.js";
5
- vi.mock("../src/utils.js", () => ({
6
- mockBase: "https://action"
7
- }));
8
- let mockRouterContext;
9
- vi.mock("../routing.js", () => ({
10
- useRouter: () => mockRouterContext,
11
- createRouterContext: () => createMockRouter(),
12
- RouterContextObj: {},
13
- RouteContextObj: {},
14
- useRoute: () => mockRouterContext.base,
15
- useResolvedPath: () => "/",
16
- useHref: () => "/",
17
- useNavigate: () => vi.fn(),
18
- useLocation: () => mockRouterContext.location,
19
- useRouteData: () => undefined,
20
- useMatch: () => null,
21
- useParams: () => ({}),
22
- useSearchParams: () => [{}, vi.fn()],
23
- useIsRouting: () => false,
24
- usePreloadRoute: () => vi.fn(),
25
- useBeforeLeave: () => vi.fn()
26
- }));
27
- describe("action", () => {
28
- beforeEach(() => {
29
- actions.clear();
30
- mockRouterContext = createMockRouter();
31
- });
32
- test("should create an action function with `url` property", () => {
33
- const testAction = action(async (data) => {
34
- return `processed: ${data}`;
35
- }, "test-action");
36
- expect(typeof testAction).toBe("function");
37
- expect(testAction.url).toBe("https://action/test-action");
38
- });
39
- test("should create action with auto-generated hash when no `name` provided", () => {
40
- const testFn = async (data) => `result: ${data}`;
41
- const testAction = action(testFn);
42
- expect(testAction.url).toMatch(/^https:\/\/action\/-?\d+$/);
43
- expect(testAction.name).toMatch(/^-?\d+$/);
44
- });
45
- test("should use it as `name` when `options` are provided as a string", () => {
46
- const testFn = async (data) => `result: ${data}`;
47
- const testAction = action(testFn, "test-action");
48
- expect(testAction.url).toMatch("https://action/test-action");
49
- expect(testAction.name).toBe("test-action");
50
- });
51
- test("should use `name` when provided in object options", () => {
52
- const testFn = async (data) => `result: ${data}`;
53
- const testAction = action(testFn, { name: "test-action" });
54
- expect(testAction.url).toMatch("https://action/test-action");
55
- expect(testAction.name).toBe("test-action");
56
- });
57
- test("should register action in actions map", () => {
58
- const testAction = action(async () => "result", "register-test");
59
- expect(actions.has(testAction.url)).toBe(true);
60
- expect(actions.get(testAction.url)).toBe(testAction);
61
- });
62
- test("should support `.with` method for currying arguments", () => {
63
- const baseAction = action(async (prefix, data) => {
64
- return `${prefix}: ${data}`;
65
- }, "with-test");
66
- const curriedAction = baseAction.with("PREFIX");
67
- expect(typeof curriedAction).toBe("function");
68
- expect(curriedAction.url).toMatch(/with-test\?args=/);
69
- });
70
- test("should execute action and create submission", async () => {
71
- return createRoot(async () => {
72
- const testAction = action(async (data) => {
73
- return `processed: ${data}`;
74
- }, "execute-test");
75
- const boundAction = useAction(testAction);
76
- const promise = boundAction("test-data");
77
- const submissions = mockRouterContext.submissions[0]();
78
- expect(submissions).toHaveLength(1);
79
- expect(submissions[0].input).toEqual(["test-data"]);
80
- expect(submissions[0].pending).toBe(true);
81
- const result = await promise;
82
- expect(result).toBe("processed: test-data");
83
- });
84
- });
85
- test("should handle action errors", async () => {
86
- return createRoot(async () => {
87
- const errorAction = action(async () => {
88
- throw new Error("Test error");
89
- }, "error-test");
90
- const boundAction = useAction(errorAction);
91
- try {
92
- await boundAction();
93
- }
94
- catch (error) {
95
- expect(error.message).toBe("Test error");
96
- }
97
- const submissions = mockRouterContext.submissions[0]();
98
- expect(submissions[0].error.message).toBe("Test error");
99
- });
100
- });
101
- test("should support `onComplete` callback", async () => {
102
- return createRoot(async () => {
103
- const onComplete = vi.fn();
104
- const testAction = action(async (data) => `result: ${data}`, {
105
- name: "callback-test",
106
- onComplete
107
- });
108
- const boundAction = useAction(testAction);
109
- await boundAction("test");
110
- expect(onComplete).toHaveBeenCalledWith(expect.objectContaining({
111
- result: "result: test",
112
- error: undefined,
113
- pending: false
114
- }));
115
- });
116
- });
117
- });
118
- describe("useSubmissions", () => {
119
- beforeEach(() => {
120
- mockRouterContext = createMockRouter();
121
- });
122
- test("should return submissions for specific action", () => {
123
- return createRoot(() => {
124
- const testAction = action(async () => "result", "submissions-test");
125
- mockRouterContext.submissions[1](submissions => [
126
- ...submissions,
127
- {
128
- input: ["data1"],
129
- url: testAction.url,
130
- result: "result1",
131
- error: undefined,
132
- pending: false,
133
- clear: vi.fn(),
134
- retry: vi.fn()
135
- },
136
- {
137
- input: ["data2"],
138
- url: testAction.url,
139
- result: undefined,
140
- error: undefined,
141
- pending: true,
142
- clear: vi.fn(),
143
- retry: vi.fn()
144
- }
145
- ]);
146
- const submissions = useSubmissions(testAction);
147
- expect(submissions).toHaveLength(2);
148
- expect(submissions[0].input).toEqual(["data1"]);
149
- expect(submissions[1].input).toEqual(["data2"]);
150
- expect(submissions.pending).toBe(true);
151
- });
152
- });
153
- test("should filter submissions when filter function provided", () => {
154
- return createRoot(() => {
155
- const testAction = action(async (data) => data, "filter-test");
156
- mockRouterContext.submissions[1](submissions => [
157
- ...submissions,
158
- {
159
- input: ["keep"],
160
- url: testAction.url,
161
- result: "result1",
162
- error: undefined,
163
- pending: false,
164
- clear: vi.fn(),
165
- retry: vi.fn()
166
- },
167
- {
168
- input: ["skip"],
169
- url: testAction.url,
170
- result: "result2",
171
- error: undefined,
172
- pending: false,
173
- clear: vi.fn(),
174
- retry: vi.fn()
175
- }
176
- ]);
177
- const submissions = useSubmissions(testAction, input => input[0] === "keep");
178
- expect(submissions).toHaveLength(1);
179
- expect(submissions[0].input).toEqual(["keep"]);
180
- });
181
- });
182
- test("should return pending false when no pending submissions", () => {
183
- return createRoot(() => {
184
- const testAction = action(async () => "result", "no-pending-test");
185
- mockRouterContext.submissions[1](submissions => [
186
- ...submissions,
187
- {
188
- input: ["data"],
189
- url: testAction.url,
190
- result: "result",
191
- error: undefined,
192
- pending: false,
193
- clear: vi.fn(),
194
- retry: vi.fn()
195
- }
196
- ]);
197
- const submissions = useSubmissions(testAction);
198
- expect(submissions.pending).toBe(false);
199
- });
200
- });
201
- });
202
- describe("useSubmission", () => {
203
- beforeEach(() => {
204
- mockRouterContext = createMockRouter();
205
- });
206
- test("should return latest submission for action", () => {
207
- return createRoot(() => {
208
- const testAction = action(async () => "result", "latest-test");
209
- mockRouterContext.submissions[1](submissions => [
210
- ...submissions,
211
- {
212
- input: ["data1"],
213
- url: testAction.url,
214
- result: "result1",
215
- error: undefined,
216
- pending: false,
217
- clear: vi.fn(),
218
- retry: vi.fn()
219
- },
220
- {
221
- input: ["data2"],
222
- url: testAction.url,
223
- result: "result2",
224
- error: undefined,
225
- pending: false,
226
- clear: vi.fn(),
227
- retry: vi.fn()
228
- }
229
- ]);
230
- const submission = useSubmission(testAction);
231
- expect(submission.input).toEqual(["data2"]);
232
- expect(submission.result).toBe("result2");
233
- });
234
- });
235
- test("should return stub when no submissions exist", () => {
236
- return createRoot(() => {
237
- const testAction = action(async () => "result", "stub-test");
238
- const submission = useSubmission(testAction);
239
- expect(submission.clear).toBeDefined();
240
- expect(submission.retry).toBeDefined();
241
- expect(typeof submission.clear).toBe("function");
242
- expect(typeof submission.retry).toBe("function");
243
- });
244
- });
245
- test("should filter submissions when filter function provided", () => {
246
- return createRoot(() => {
247
- const testAction = action(async (data) => data, "filter-submission-test");
248
- mockRouterContext.submissions[1](submissions => [
249
- ...submissions,
250
- {
251
- input: ["skip"],
252
- url: testAction.url,
253
- result: "result1",
254
- error: undefined,
255
- pending: false,
256
- clear: vi.fn(),
257
- retry: vi.fn()
258
- },
259
- {
260
- input: ["keep"],
261
- url: testAction.url,
262
- result: "result2",
263
- error: undefined,
264
- pending: false,
265
- clear: vi.fn(),
266
- retry: vi.fn()
267
- }
268
- ]);
269
- const submission = useSubmission(testAction, input => input[0] === "keep");
270
- expect(submission.input).toEqual(["keep"]);
271
- expect(submission.result).toBe("result2");
272
- });
273
- });
274
- });
275
- describe("useAction", () => {
276
- beforeEach(() => {
277
- mockRouterContext = createMockRouter();
278
- });
279
- test("should return bound action function", () => {
280
- return createRoot(() => {
281
- const testAction = action(async (data) => `result: ${data}`, "bound-test");
282
- const boundAction = useAction(testAction);
283
- expect(typeof boundAction).toBe("function");
284
- });
285
- });
286
- test("should execute action through useAction", async () => {
287
- return createRoot(async () => {
288
- const testAction = action(async (data) => {
289
- await new Promise(resolve => setTimeout(resolve, 1));
290
- return `result: ${data}`;
291
- }, "context-test");
292
- const boundAction = useAction(testAction);
293
- const result = await boundAction("test-data");
294
- expect(result).toBe("result: test-data");
295
- });
296
- });
297
- });
@@ -1,32 +0,0 @@
1
- import { type ReconcileOptions } from "solid-js/store";
2
- /**
3
- * As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
4
- * this type allows to support `latest` field for these primitives.
5
- * It will be removed in the future.
6
- */
7
- export type AccessorWithLatest<T> = {
8
- (): T;
9
- latest: T;
10
- };
11
- export declare function createAsync<T>(fn: (prev: T) => Promise<T>, options: {
12
- name?: string;
13
- initialValue: T;
14
- deferStream?: boolean;
15
- }): AccessorWithLatest<T>;
16
- export declare function createAsync<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
17
- name?: string;
18
- initialValue?: T;
19
- deferStream?: boolean;
20
- }): AccessorWithLatest<T | undefined>;
21
- export declare function createAsyncStore<T>(fn: (prev: T) => Promise<T>, options: {
22
- name?: string;
23
- initialValue: T;
24
- deferStream?: boolean;
25
- reconcile?: ReconcileOptions;
26
- }): AccessorWithLatest<T>;
27
- export declare function createAsyncStore<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
28
- name?: string;
29
- initialValue?: T;
30
- deferStream?: boolean;
31
- reconcile?: ReconcileOptions;
32
- }): AccessorWithLatest<T | undefined>;
@@ -1,96 +0,0 @@
1
- /**
2
- * This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
3
- */
4
- import { createResource, sharedConfig, untrack, catchError } from "solid-js";
5
- import { createStore, reconcile, unwrap } from "solid-js/store";
6
- import { isServer } from "solid-js/web";
7
- import { setFunctionName } from "../utils.js";
8
- export function createAsync(fn, options) {
9
- let resource;
10
- let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
11
- [resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, options);
12
- const resultAccessor = (() => resource());
13
- if (options?.name)
14
- setFunctionName(resultAccessor, options.name);
15
- Object.defineProperty(resultAccessor, "latest", {
16
- get() {
17
- return resource.latest;
18
- }
19
- });
20
- return resultAccessor;
21
- }
22
- export function createAsyncStore(fn, options = {}) {
23
- let resource;
24
- let prev = () => !resource || resource.state === "unresolved"
25
- ? undefined
26
- : unwrap(resource.latest);
27
- [resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, {
28
- ...options,
29
- storage: (init) => createDeepSignal(init, options.reconcile)
30
- });
31
- const resultAccessor = (() => resource());
32
- Object.defineProperty(resultAccessor, "latest", {
33
- get() {
34
- return resource.latest;
35
- }
36
- });
37
- return resultAccessor;
38
- }
39
- function createDeepSignal(value, options) {
40
- const [store, setStore] = createStore({
41
- value: structuredClone(value)
42
- });
43
- return [
44
- () => store.value,
45
- (v) => {
46
- typeof v === "function" && (v = v());
47
- setStore("value", reconcile(structuredClone(v), options));
48
- return store.value;
49
- }
50
- ];
51
- }
52
- // mock promise while hydrating to prevent fetching
53
- class MockPromise {
54
- static all() {
55
- return new MockPromise();
56
- }
57
- static allSettled() {
58
- return new MockPromise();
59
- }
60
- static any() {
61
- return new MockPromise();
62
- }
63
- static race() {
64
- return new MockPromise();
65
- }
66
- static reject() {
67
- return new MockPromise();
68
- }
69
- static resolve() {
70
- return new MockPromise();
71
- }
72
- catch() {
73
- return new MockPromise();
74
- }
75
- then() {
76
- return new MockPromise();
77
- }
78
- finally() {
79
- return new MockPromise();
80
- }
81
- }
82
- function subFetch(fn, prev) {
83
- if (isServer || !sharedConfig.context)
84
- return fn(prev);
85
- const ogFetch = fetch;
86
- const ogPromise = Promise;
87
- try {
88
- window.fetch = () => new MockPromise();
89
- Promise = MockPromise;
90
- return fn(prev);
91
- }
92
- finally {
93
- window.fetch = ogFetch;
94
- Promise = ogPromise;
95
- }
96
- }
@@ -1 +0,0 @@
1
- export {};