rask-ui 0.25.0 → 0.25.4
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.
- package/dist/component.d.ts +1 -0
- package/dist/component.d.ts.map +1 -1
- package/dist/component.js +5 -4
- package/dist/createContext.d.ts.map +1 -1
- package/dist/createContext.js +1 -4
- package/package.json +2 -2
- package/dist/asyncState.d.ts +0 -16
- package/dist/asyncState.d.ts.map +0 -1
- package/dist/asyncState.js +0 -24
- package/dist/compiler.d.ts +0 -2
- package/dist/compiler.d.ts.map +0 -1
- package/dist/compiler.js +0 -1
- package/dist/context.d.ts +0 -5
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -29
- package/dist/createAsync.d.ts +0 -39
- package/dist/createAsync.d.ts.map +0 -1
- package/dist/createAsync.js +0 -47
- package/dist/createAsync.test.d.ts +0 -2
- package/dist/createAsync.test.d.ts.map +0 -1
- package/dist/createAsync.test.js +0 -110
- package/dist/createMutation.d.ts +0 -43
- package/dist/createMutation.d.ts.map +0 -1
- package/dist/createMutation.js +0 -76
- package/dist/createMutation.test.d.ts +0 -2
- package/dist/createMutation.test.d.ts.map +0 -1
- package/dist/createMutation.test.js +0 -168
- package/dist/createQuery.d.ts +0 -42
- package/dist/createQuery.d.ts.map +0 -1
- package/dist/createQuery.js +0 -80
- package/dist/createQuery.test.d.ts +0 -2
- package/dist/createQuery.test.d.ts.map +0 -1
- package/dist/createQuery.test.js +0 -156
- package/dist/createRef.d.ts +0 -6
- package/dist/createRef.d.ts.map +0 -1
- package/dist/createRef.js +0 -8
- package/dist/createState.d.ts +0 -26
- package/dist/createState.d.ts.map +0 -1
- package/dist/createState.js +0 -94
- package/dist/createState.test.d.ts +0 -2
- package/dist/createState.test.d.ts.map +0 -1
- package/dist/createState.test.js +0 -111
- package/dist/createView.d.ts +0 -54
- package/dist/createView.d.ts.map +0 -1
- package/dist/createView.js +0 -68
- package/dist/createView.test.d.ts +0 -2
- package/dist/createView.test.d.ts.map +0 -1
- package/dist/createView.test.js +0 -203
- package/dist/error.d.ts +0 -16
- package/dist/error.d.ts.map +0 -1
- package/dist/error.js +0 -17
- package/dist/jsx.d.ts +0 -257
- package/dist/observation.test.d.ts +0 -2
- package/dist/observation.test.d.ts.map +0 -1
- package/dist/observation.test.js +0 -150
- package/dist/suspense.d.ts +0 -25
- package/dist/suspense.d.ts.map +0 -1
- package/dist/suspense.js +0 -97
- package/dist/test-setup.d.ts +0 -16
- package/dist/test-setup.d.ts.map +0 -1
- package/dist/test-setup.js +0 -40
- package/dist/test.d.ts +0 -2
- package/dist/test.d.ts.map +0 -1
- package/dist/test.js +0 -24
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { createMutation } from './createMutation';
|
|
3
|
-
describe('createMutation', () => {
|
|
4
|
-
it('should start in idle state', () => {
|
|
5
|
-
const mutator = vi.fn(() => Promise.resolve(null));
|
|
6
|
-
const mutation = createMutation(mutator);
|
|
7
|
-
expect(mutation.isPending).toBe(false);
|
|
8
|
-
expect(mutation.params).toBeNull();
|
|
9
|
-
expect(mutation.error).toBeNull();
|
|
10
|
-
expect(mutator).not.toHaveBeenCalled();
|
|
11
|
-
});
|
|
12
|
-
it('should execute mutator when mutate is called', async () => {
|
|
13
|
-
const mutator = vi.fn((params) => Promise.resolve(params));
|
|
14
|
-
const mutation = createMutation(mutator);
|
|
15
|
-
mutation.mutate('test');
|
|
16
|
-
expect(mutation.isPending).toBe(true);
|
|
17
|
-
expect(mutation.params).toBe('test');
|
|
18
|
-
expect(mutator).toHaveBeenCalledWith('test');
|
|
19
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
20
|
-
expect(mutation.isPending).toBe(false);
|
|
21
|
-
expect(mutation.params).toBeNull();
|
|
22
|
-
});
|
|
23
|
-
it('should handle successful mutations', async () => {
|
|
24
|
-
const mutator = (params) => Promise.resolve(params);
|
|
25
|
-
const mutation = createMutation(mutator);
|
|
26
|
-
mutation.mutate({ id: 1 });
|
|
27
|
-
expect(mutation.isPending).toBe(true);
|
|
28
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
29
|
-
expect(mutation.isPending).toBe(false);
|
|
30
|
-
expect(mutation.error).toBeNull();
|
|
31
|
-
expect(mutation.params).toBeNull();
|
|
32
|
-
});
|
|
33
|
-
it('should handle mutation errors', async () => {
|
|
34
|
-
const mutator = (params) => Promise.reject(new Error('Mutation failed'));
|
|
35
|
-
const mutation = createMutation(mutator);
|
|
36
|
-
mutation.mutate('test');
|
|
37
|
-
expect(mutation.isPending).toBe(true);
|
|
38
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
39
|
-
expect(mutation.isPending).toBe(false);
|
|
40
|
-
expect(mutation.error).toContain('Mutation failed');
|
|
41
|
-
expect(mutation.params).toBeNull();
|
|
42
|
-
});
|
|
43
|
-
it('should cancel previous mutation on new mutate call', async () => {
|
|
44
|
-
let resolveFirst;
|
|
45
|
-
let resolveSecond;
|
|
46
|
-
const firstPromise = new Promise((resolve) => {
|
|
47
|
-
resolveFirst = resolve;
|
|
48
|
-
});
|
|
49
|
-
const secondPromise = new Promise((resolve) => {
|
|
50
|
-
resolveSecond = resolve;
|
|
51
|
-
});
|
|
52
|
-
const mutator = vi
|
|
53
|
-
.fn()
|
|
54
|
-
.mockReturnValueOnce(firstPromise)
|
|
55
|
-
.mockReturnValueOnce(secondPromise);
|
|
56
|
-
const mutation = createMutation(mutator);
|
|
57
|
-
mutation.mutate('first');
|
|
58
|
-
expect(mutation.params).toBe('first');
|
|
59
|
-
// Trigger second mutation before first completes
|
|
60
|
-
mutation.mutate('second');
|
|
61
|
-
expect(mutation.params).toBe('second');
|
|
62
|
-
// Resolve first (should be ignored due to cancellation)
|
|
63
|
-
resolveFirst('first');
|
|
64
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
65
|
-
expect(mutation.isPending).toBe(true); // Still pending second
|
|
66
|
-
// Resolve second
|
|
67
|
-
resolveSecond('second');
|
|
68
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
69
|
-
expect(mutation.isPending).toBe(false);
|
|
70
|
-
expect(mutation.params).toBeNull();
|
|
71
|
-
});
|
|
72
|
-
it('should handle rapid successive mutations', async () => {
|
|
73
|
-
let counter = 0;
|
|
74
|
-
const mutator = vi.fn(() => Promise.resolve(++counter));
|
|
75
|
-
const mutation = createMutation(mutator);
|
|
76
|
-
// Rapid mutations
|
|
77
|
-
mutation.mutate('1');
|
|
78
|
-
mutation.mutate('2');
|
|
79
|
-
mutation.mutate('3');
|
|
80
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
81
|
-
// Only the last mutation should complete
|
|
82
|
-
expect(mutator).toHaveBeenCalledTimes(3);
|
|
83
|
-
expect(mutation.isPending).toBe(false);
|
|
84
|
-
expect(mutation.params).toBeNull();
|
|
85
|
-
});
|
|
86
|
-
it('should clear error on successful retry', async () => {
|
|
87
|
-
const mutator = vi
|
|
88
|
-
.fn()
|
|
89
|
-
.mockRejectedValueOnce(new Error('First error'))
|
|
90
|
-
.mockResolvedValueOnce('success');
|
|
91
|
-
const mutation = createMutation(mutator);
|
|
92
|
-
mutation.mutate('attempt1');
|
|
93
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
94
|
-
expect(mutation.error).toContain('First error');
|
|
95
|
-
mutation.mutate('attempt2');
|
|
96
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
97
|
-
expect(mutation.error).toBeNull();
|
|
98
|
-
expect(mutation.isPending).toBe(false);
|
|
99
|
-
});
|
|
100
|
-
it('should handle different parameter types', async () => {
|
|
101
|
-
const mutator = vi.fn((params) => Promise.resolve(params));
|
|
102
|
-
const mutation = createMutation(mutator);
|
|
103
|
-
// Object params
|
|
104
|
-
mutation.mutate({ id: 1, name: 'test' });
|
|
105
|
-
expect(mutation.params).toEqual({ id: 1, name: 'test' });
|
|
106
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
107
|
-
// Array params
|
|
108
|
-
const mutation2 = createMutation(mutator);
|
|
109
|
-
mutation2.mutate([1, 2, 3]);
|
|
110
|
-
expect(mutation2.params).toEqual([1, 2, 3]);
|
|
111
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
112
|
-
// String params
|
|
113
|
-
const mutation3 = createMutation(mutator);
|
|
114
|
-
mutation3.mutate('string');
|
|
115
|
-
expect(mutation3.params).toBe('string');
|
|
116
|
-
});
|
|
117
|
-
it('should convert errors to strings', async () => {
|
|
118
|
-
const mutator = (params) => Promise.reject('string error');
|
|
119
|
-
const mutation = createMutation(mutator);
|
|
120
|
-
mutation.mutate('test');
|
|
121
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
122
|
-
expect(typeof mutation.error).toBe('string');
|
|
123
|
-
expect(mutation.error).toBe('string error');
|
|
124
|
-
});
|
|
125
|
-
it('should handle AbortController cancellation correctly', async () => {
|
|
126
|
-
const abortedPromise = new Promise((_, reject) => {
|
|
127
|
-
const error = new Error('Aborted');
|
|
128
|
-
error.name = 'AbortError';
|
|
129
|
-
setTimeout(() => reject(error), 5);
|
|
130
|
-
});
|
|
131
|
-
const successPromise = Promise.resolve('success');
|
|
132
|
-
const mutator = vi
|
|
133
|
-
.fn()
|
|
134
|
-
.mockReturnValueOnce(abortedPromise)
|
|
135
|
-
.mockReturnValueOnce(successPromise);
|
|
136
|
-
const mutation = createMutation(mutator);
|
|
137
|
-
mutation.mutate('first');
|
|
138
|
-
// Immediately trigger second mutation to abort first
|
|
139
|
-
mutation.mutate('second');
|
|
140
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
141
|
-
expect(mutation.isPending).toBe(false);
|
|
142
|
-
expect(mutation.error).toBeNull();
|
|
143
|
-
});
|
|
144
|
-
it('should track params during pending state', () => {
|
|
145
|
-
const mutator = () => new Promise((resolve) => setTimeout(() => resolve(null), 100));
|
|
146
|
-
const mutation = createMutation(mutator);
|
|
147
|
-
const params = { id: 123, action: 'update' };
|
|
148
|
-
mutation.mutate(params);
|
|
149
|
-
expect(mutation.isPending).toBe(true);
|
|
150
|
-
expect(mutation.params).toEqual(params);
|
|
151
|
-
});
|
|
152
|
-
it('should expose reactive getters', async () => {
|
|
153
|
-
const mutator = () => Promise.resolve('data');
|
|
154
|
-
const mutation = createMutation(mutator);
|
|
155
|
-
// Access getters before mutation
|
|
156
|
-
expect(mutation.isPending).toBe(false);
|
|
157
|
-
expect(mutation.params).toBeNull();
|
|
158
|
-
expect(mutation.error).toBeNull();
|
|
159
|
-
mutation.mutate('test');
|
|
160
|
-
// Access getters during mutation
|
|
161
|
-
expect(mutation.isPending).toBe(true);
|
|
162
|
-
expect(mutation.params).toBe('test');
|
|
163
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
164
|
-
// Access getters after mutation
|
|
165
|
-
expect(mutation.isPending).toBe(false);
|
|
166
|
-
expect(mutation.params).toBeNull();
|
|
167
|
-
});
|
|
168
|
-
});
|
package/dist/createQuery.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
type QueryState<T> = {
|
|
2
|
-
isPending: true;
|
|
3
|
-
data: T | null;
|
|
4
|
-
error: null;
|
|
5
|
-
} | {
|
|
6
|
-
isPending: false;
|
|
7
|
-
data: T;
|
|
8
|
-
error: null;
|
|
9
|
-
} | {
|
|
10
|
-
isPending: false;
|
|
11
|
-
data: null;
|
|
12
|
-
error: string;
|
|
13
|
-
};
|
|
14
|
-
export type Query<T> = QueryState<T> & {
|
|
15
|
-
fetch(force?: boolean): void;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Creates a reactive query that manages data fetching with loading and error states.
|
|
19
|
-
*
|
|
20
|
-
* @warning **Do not destructure the returned reactive object!** Destructuring breaks reactivity.
|
|
21
|
-
* Access properties directly in your render function instead.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* // ❌ Bad - destructuring loses reactivity
|
|
25
|
-
* function Component() {
|
|
26
|
-
* const query = createQuery(() => fetchUsers());
|
|
27
|
-
* const { isPending, data, error } = query; // Don't do this!
|
|
28
|
-
* return () => <div>{isPending ? "Loading..." : data.length}</div>; // Won't update!
|
|
29
|
-
* }
|
|
30
|
-
*
|
|
31
|
-
* // ✅ Good - access properties directly
|
|
32
|
-
* function Component() {
|
|
33
|
-
* const query = createQuery(() => fetchUsers());
|
|
34
|
-
* return () => <div>{query.isPending ? "Loading..." : query.data.length}</div>;
|
|
35
|
-
* }
|
|
36
|
-
*
|
|
37
|
-
* @param fetcher - Function that returns a promise with the data to fetch
|
|
38
|
-
* @returns Reactive query object with isPending, data, error properties and fetch method
|
|
39
|
-
*/
|
|
40
|
-
export declare function createQuery<T>(fetcher: () => Promise<T>): Query<T>;
|
|
41
|
-
export {};
|
|
42
|
-
//# sourceMappingURL=createQuery.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createQuery.d.ts","sourceRoot":"","sources":["../src/createQuery.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,CAAC,CAAC,IACb;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG;IACrC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CA+DlE"}
|
package/dist/createQuery.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { createState } from "./createState";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a reactive query that manages data fetching with loading and error states.
|
|
4
|
-
*
|
|
5
|
-
* @warning **Do not destructure the returned reactive object!** Destructuring breaks reactivity.
|
|
6
|
-
* Access properties directly in your render function instead.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* // ❌ Bad - destructuring loses reactivity
|
|
10
|
-
* function Component() {
|
|
11
|
-
* const query = createQuery(() => fetchUsers());
|
|
12
|
-
* const { isPending, data, error } = query; // Don't do this!
|
|
13
|
-
* return () => <div>{isPending ? "Loading..." : data.length}</div>; // Won't update!
|
|
14
|
-
* }
|
|
15
|
-
*
|
|
16
|
-
* // ✅ Good - access properties directly
|
|
17
|
-
* function Component() {
|
|
18
|
-
* const query = createQuery(() => fetchUsers());
|
|
19
|
-
* return () => <div>{query.isPending ? "Loading..." : query.data.length}</div>;
|
|
20
|
-
* }
|
|
21
|
-
*
|
|
22
|
-
* @param fetcher - Function that returns a promise with the data to fetch
|
|
23
|
-
* @returns Reactive query object with isPending, data, error properties and fetch method
|
|
24
|
-
*/
|
|
25
|
-
export function createQuery(fetcher) {
|
|
26
|
-
const state = createState({
|
|
27
|
-
isPending: true,
|
|
28
|
-
data: null,
|
|
29
|
-
error: null,
|
|
30
|
-
});
|
|
31
|
-
const assign = (newState) => {
|
|
32
|
-
Object.assign(state, newState);
|
|
33
|
-
};
|
|
34
|
-
let currentAbortController;
|
|
35
|
-
const fetch = () => {
|
|
36
|
-
currentAbortController?.abort();
|
|
37
|
-
const abortController = (currentAbortController = new AbortController());
|
|
38
|
-
fetcher()
|
|
39
|
-
.then((data) => {
|
|
40
|
-
if (abortController.signal.aborted) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
assign({
|
|
44
|
-
isPending: false,
|
|
45
|
-
data,
|
|
46
|
-
error: null,
|
|
47
|
-
});
|
|
48
|
-
})
|
|
49
|
-
.catch((error) => {
|
|
50
|
-
if (abortController.signal.aborted) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
assign({
|
|
54
|
-
isPending: false,
|
|
55
|
-
data: null,
|
|
56
|
-
error: String(error),
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
};
|
|
60
|
-
fetch();
|
|
61
|
-
return {
|
|
62
|
-
get isPending() {
|
|
63
|
-
return state.isPending;
|
|
64
|
-
},
|
|
65
|
-
get data() {
|
|
66
|
-
return state.data;
|
|
67
|
-
},
|
|
68
|
-
get error() {
|
|
69
|
-
return state.error;
|
|
70
|
-
},
|
|
71
|
-
fetch(force) {
|
|
72
|
-
assign({
|
|
73
|
-
isPending: true,
|
|
74
|
-
data: force ? null : state.data,
|
|
75
|
-
error: null,
|
|
76
|
-
});
|
|
77
|
-
fetch();
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createQuery.test.d.ts","sourceRoot":"","sources":["../src/createQuery.test.ts"],"names":[],"mappings":""}
|
package/dist/createQuery.test.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { createQuery } from './createQuery';
|
|
3
|
-
describe('createQuery', () => {
|
|
4
|
-
it('should start in pending state and fetch immediately', async () => {
|
|
5
|
-
const fetcher = vi.fn(() => Promise.resolve('data'));
|
|
6
|
-
const query = createQuery(fetcher);
|
|
7
|
-
expect(query.isPending).toBe(true);
|
|
8
|
-
expect(query.data).toBeNull();
|
|
9
|
-
expect(query.error).toBeNull();
|
|
10
|
-
expect(fetcher).toHaveBeenCalledTimes(1);
|
|
11
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
12
|
-
expect(query.isPending).toBe(false);
|
|
13
|
-
expect(query.data).toBe('data');
|
|
14
|
-
});
|
|
15
|
-
it('should resolve to data state on success', async () => {
|
|
16
|
-
const fetcher = () => Promise.resolve({ id: 1, name: 'Test' });
|
|
17
|
-
const query = createQuery(fetcher);
|
|
18
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
19
|
-
expect(query.isPending).toBe(false);
|
|
20
|
-
expect(query.data).toEqual({ id: 1, name: 'Test' });
|
|
21
|
-
expect(query.error).toBeNull();
|
|
22
|
-
});
|
|
23
|
-
it('should resolve to error state on failure', async () => {
|
|
24
|
-
const fetcher = () => Promise.reject(new Error('Network error'));
|
|
25
|
-
const query = createQuery(fetcher);
|
|
26
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
27
|
-
expect(query.isPending).toBe(false);
|
|
28
|
-
expect(query.data).toBeNull();
|
|
29
|
-
expect(query.error).toContain('Network error');
|
|
30
|
-
});
|
|
31
|
-
it('should allow manual refetch', async () => {
|
|
32
|
-
const fetcher = vi.fn(() => Promise.resolve('data'));
|
|
33
|
-
const query = createQuery(fetcher);
|
|
34
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
35
|
-
expect(fetcher).toHaveBeenCalledTimes(1);
|
|
36
|
-
query.fetch();
|
|
37
|
-
expect(query.isPending).toBe(true);
|
|
38
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
39
|
-
expect(fetcher).toHaveBeenCalledTimes(2);
|
|
40
|
-
expect(query.isPending).toBe(false);
|
|
41
|
-
});
|
|
42
|
-
it('should retain old data during refetch by default', async () => {
|
|
43
|
-
const fetcher = vi
|
|
44
|
-
.fn()
|
|
45
|
-
.mockResolvedValueOnce('data1')
|
|
46
|
-
.mockResolvedValueOnce('data2');
|
|
47
|
-
const query = createQuery(fetcher);
|
|
48
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
49
|
-
expect(query.data).toBe('data1');
|
|
50
|
-
query.fetch();
|
|
51
|
-
expect(query.isPending).toBe(true);
|
|
52
|
-
expect(query.data).toBe('data1'); // Old data retained
|
|
53
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
54
|
-
expect(query.data).toBe('data2');
|
|
55
|
-
});
|
|
56
|
-
it('should clear old data when force refetch is used', async () => {
|
|
57
|
-
const fetcher = vi
|
|
58
|
-
.fn()
|
|
59
|
-
.mockResolvedValueOnce('data1')
|
|
60
|
-
.mockResolvedValueOnce('data2');
|
|
61
|
-
const query = createQuery(fetcher);
|
|
62
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
63
|
-
expect(query.data).toBe('data1');
|
|
64
|
-
query.fetch(true); // Force refresh
|
|
65
|
-
expect(query.isPending).toBe(true);
|
|
66
|
-
expect(query.data).toBeNull(); // Old data cleared
|
|
67
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
68
|
-
expect(query.data).toBe('data2');
|
|
69
|
-
});
|
|
70
|
-
it('should cancel previous request on new fetch', async () => {
|
|
71
|
-
let resolveFirst;
|
|
72
|
-
let resolveSecond;
|
|
73
|
-
const firstPromise = new Promise((resolve) => {
|
|
74
|
-
resolveFirst = resolve;
|
|
75
|
-
});
|
|
76
|
-
const secondPromise = new Promise((resolve) => {
|
|
77
|
-
resolveSecond = resolve;
|
|
78
|
-
});
|
|
79
|
-
const fetcher = vi
|
|
80
|
-
.fn()
|
|
81
|
-
.mockReturnValueOnce(firstPromise)
|
|
82
|
-
.mockReturnValueOnce(secondPromise);
|
|
83
|
-
const query = createQuery(fetcher);
|
|
84
|
-
expect(query.isPending).toBe(true);
|
|
85
|
-
// Trigger second fetch before first completes
|
|
86
|
-
query.fetch();
|
|
87
|
-
// Resolve first (should be ignored due to cancellation)
|
|
88
|
-
resolveFirst('first');
|
|
89
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
90
|
-
expect(query.data).toBeNull(); // First result ignored
|
|
91
|
-
// Resolve second
|
|
92
|
-
resolveSecond('second');
|
|
93
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
94
|
-
expect(query.data).toBe('second');
|
|
95
|
-
});
|
|
96
|
-
it('should handle rapid successive fetches', async () => {
|
|
97
|
-
let counter = 0;
|
|
98
|
-
const fetcher = vi.fn(() => Promise.resolve(`data-${++counter}`));
|
|
99
|
-
const query = createQuery(fetcher);
|
|
100
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
101
|
-
// Rapid fetches
|
|
102
|
-
query.fetch();
|
|
103
|
-
query.fetch();
|
|
104
|
-
query.fetch();
|
|
105
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
106
|
-
// Only the last fetch should matter
|
|
107
|
-
expect(fetcher).toHaveBeenCalledTimes(4); // Initial + 3 fetches
|
|
108
|
-
expect(query.data).toBe('data-4');
|
|
109
|
-
});
|
|
110
|
-
it('should cancel on error and allow refetch', async () => {
|
|
111
|
-
const fetcher = vi
|
|
112
|
-
.fn()
|
|
113
|
-
.mockRejectedValueOnce(new Error('First error'))
|
|
114
|
-
.mockResolvedValueOnce('success');
|
|
115
|
-
const query = createQuery(fetcher);
|
|
116
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
117
|
-
expect(query.error).toContain('First error');
|
|
118
|
-
expect(query.data).toBeNull();
|
|
119
|
-
query.fetch();
|
|
120
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
121
|
-
expect(query.error).toBeNull();
|
|
122
|
-
expect(query.data).toBe('success');
|
|
123
|
-
});
|
|
124
|
-
it('should handle AbortController cancellation correctly', async () => {
|
|
125
|
-
const abortedPromise = new Promise((_, reject) => {
|
|
126
|
-
const error = new Error('Aborted');
|
|
127
|
-
error.name = 'AbortError';
|
|
128
|
-
setTimeout(() => reject(error), 5);
|
|
129
|
-
});
|
|
130
|
-
const successPromise = Promise.resolve('success');
|
|
131
|
-
const fetcher = vi
|
|
132
|
-
.fn()
|
|
133
|
-
.mockReturnValueOnce(abortedPromise)
|
|
134
|
-
.mockReturnValueOnce(successPromise);
|
|
135
|
-
const query = createQuery(fetcher);
|
|
136
|
-
// Immediately trigger second fetch to abort first
|
|
137
|
-
query.fetch();
|
|
138
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
139
|
-
expect(query.data).toBe('success');
|
|
140
|
-
expect(query.error).toBeNull();
|
|
141
|
-
});
|
|
142
|
-
it('should expose reactive getters', async () => {
|
|
143
|
-
const fetcher = () => Promise.resolve('data');
|
|
144
|
-
const query = createQuery(fetcher);
|
|
145
|
-
// Access getters
|
|
146
|
-
const pending1 = query.isPending;
|
|
147
|
-
const data1 = query.data;
|
|
148
|
-
const error1 = query.error;
|
|
149
|
-
expect(pending1).toBe(true);
|
|
150
|
-
expect(data1).toBeNull();
|
|
151
|
-
expect(error1).toBeNull();
|
|
152
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
153
|
-
expect(query.isPending).toBe(false);
|
|
154
|
-
expect(query.data).toBe('data');
|
|
155
|
-
});
|
|
156
|
-
});
|
package/dist/createRef.d.ts
DELETED
package/dist/createRef.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createRef.d.ts","sourceRoot":"","sources":["../src/createRef.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI;WAChD,CAAC,GAAG,IAAI;;mBADe,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI;EASpE"}
|
package/dist/createRef.js
DELETED
package/dist/createState.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a reactive state object that tracks property access and notifies observers on changes.
|
|
3
|
-
*
|
|
4
|
-
* @warning **Do not destructure the returned reactive object!** Destructuring breaks reactivity
|
|
5
|
-
* because it extracts plain values instead of maintaining proxy access. This is the same rule
|
|
6
|
-
* as Solid.js signals.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* // ❌ Bad - destructuring loses reactivity
|
|
10
|
-
* function Component(props) {
|
|
11
|
-
* const state = createState({ count: 0, name: "foo" });
|
|
12
|
-
* const { count, name } = state; // Don't do this!
|
|
13
|
-
* return () => <div>{count} {name}</div>; // Won't update!
|
|
14
|
-
* }
|
|
15
|
-
*
|
|
16
|
-
* // ✅ Good - access properties directly in render
|
|
17
|
-
* function Component(props) {
|
|
18
|
-
* const state = createState({ count: 0, name: "foo" });
|
|
19
|
-
* return () => <div>{state.count} {state.name}</div>; // Reactive!
|
|
20
|
-
* }
|
|
21
|
-
*
|
|
22
|
-
* @param state - The initial state object to make reactive
|
|
23
|
-
* @returns A reactive proxy of the state object
|
|
24
|
-
*/
|
|
25
|
-
export declare function createState<T extends object>(state: T): T;
|
|
26
|
-
//# sourceMappingURL=createState.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createState.d.ts","sourceRoot":"","sources":["../src/createState.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEzD"}
|
package/dist/createState.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { getCurrentObserver, Signal } from "./observation";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a reactive state object that tracks property access and notifies observers on changes.
|
|
4
|
-
*
|
|
5
|
-
* @warning **Do not destructure the returned reactive object!** Destructuring breaks reactivity
|
|
6
|
-
* because it extracts plain values instead of maintaining proxy access. This is the same rule
|
|
7
|
-
* as Solid.js signals.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* // ❌ Bad - destructuring loses reactivity
|
|
11
|
-
* function Component(props) {
|
|
12
|
-
* const state = createState({ count: 0, name: "foo" });
|
|
13
|
-
* const { count, name } = state; // Don't do this!
|
|
14
|
-
* return () => <div>{count} {name}</div>; // Won't update!
|
|
15
|
-
* }
|
|
16
|
-
*
|
|
17
|
-
* // ✅ Good - access properties directly in render
|
|
18
|
-
* function Component(props) {
|
|
19
|
-
* const state = createState({ count: 0, name: "foo" });
|
|
20
|
-
* return () => <div>{state.count} {state.name}</div>; // Reactive!
|
|
21
|
-
* }
|
|
22
|
-
*
|
|
23
|
-
* @param state - The initial state object to make reactive
|
|
24
|
-
* @returns A reactive proxy of the state object
|
|
25
|
-
*/
|
|
26
|
-
export function createState(state) {
|
|
27
|
-
return getProxy(state);
|
|
28
|
-
}
|
|
29
|
-
const proxyCache = new WeakMap();
|
|
30
|
-
const PROXY_MARKER = Symbol("isProxy");
|
|
31
|
-
function getProxy(value) {
|
|
32
|
-
// Check if already a proxy to avoid double-wrapping
|
|
33
|
-
if (PROXY_MARKER in value) {
|
|
34
|
-
return value;
|
|
35
|
-
}
|
|
36
|
-
if (proxyCache.has(value)) {
|
|
37
|
-
return proxyCache.get(value);
|
|
38
|
-
}
|
|
39
|
-
const signals = {};
|
|
40
|
-
const proxy = new Proxy(value, {
|
|
41
|
-
has(target, key) {
|
|
42
|
-
// Support the "in" operator check for PROXY_MARKER
|
|
43
|
-
if (key === PROXY_MARKER) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
return Reflect.has(target, key);
|
|
47
|
-
},
|
|
48
|
-
get(target, key) {
|
|
49
|
-
// Mark this as a proxy to prevent double-wrapping
|
|
50
|
-
if (key === PROXY_MARKER) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
const value = Reflect.get(target, key);
|
|
54
|
-
if (typeof key === "symbol" || typeof value === "function") {
|
|
55
|
-
return value;
|
|
56
|
-
}
|
|
57
|
-
const observer = getCurrentObserver();
|
|
58
|
-
if (observer) {
|
|
59
|
-
const signal = (signals[key] = signals[key] || new Signal());
|
|
60
|
-
observer.subscribeSignal(signal);
|
|
61
|
-
}
|
|
62
|
-
if (Array.isArray(value) ||
|
|
63
|
-
(typeof value === "object" && value !== null)) {
|
|
64
|
-
return getProxy(value);
|
|
65
|
-
}
|
|
66
|
-
return value;
|
|
67
|
-
},
|
|
68
|
-
set(target, key, newValue) {
|
|
69
|
-
if (typeof key === "symbol") {
|
|
70
|
-
return Reflect.set(target, key, newValue);
|
|
71
|
-
}
|
|
72
|
-
const oldValue = Reflect.get(target, key);
|
|
73
|
-
const setResult = Reflect.set(target, key, newValue);
|
|
74
|
-
// We only notify if actual change, though array length actually updates under the hood
|
|
75
|
-
if (newValue !== oldValue || (Array.isArray(value) && key === "length")) {
|
|
76
|
-
console.log("WTF", key, newValue);
|
|
77
|
-
const signal = signals[key];
|
|
78
|
-
signal?.notify();
|
|
79
|
-
}
|
|
80
|
-
return setResult;
|
|
81
|
-
},
|
|
82
|
-
deleteProperty(target, key) {
|
|
83
|
-
if (typeof key === "symbol") {
|
|
84
|
-
return Reflect.deleteProperty(target, key);
|
|
85
|
-
}
|
|
86
|
-
const signal = signals[key];
|
|
87
|
-
signal?.notify();
|
|
88
|
-
delete signals[key];
|
|
89
|
-
return Reflect.deleteProperty(target, key);
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
proxyCache.set(value, proxy);
|
|
93
|
-
return proxy;
|
|
94
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createState.test.d.ts","sourceRoot":"","sources":["../src/createState.test.ts"],"names":[],"mappings":""}
|