@esportsplus/reactivity 0.22.3 → 0.23.1
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/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/reactive/array.d.ts +3 -0
- package/build/reactive/array.js +32 -2
- package/build/reactive/index.d.ts +17 -14
- package/build/reactive/index.js +7 -25
- package/build/system.js +1 -1
- package/build/transformer/detector.d.ts +2 -0
- package/build/transformer/detector.js +38 -0
- package/build/transformer/index.d.ts +10 -0
- package/build/transformer/index.js +55 -0
- package/build/transformer/plugins/esbuild.d.ts +5 -0
- package/build/transformer/plugins/esbuild.js +31 -0
- package/build/transformer/plugins/tsc.d.ts +3 -0
- package/build/transformer/plugins/tsc.js +4 -0
- package/build/transformer/plugins/vite.d.ts +5 -0
- package/build/transformer/plugins/vite.js +28 -0
- package/build/transformer/transforms/auto-dispose.d.ts +3 -0
- package/build/transformer/transforms/auto-dispose.js +119 -0
- package/build/transformer/transforms/reactive-array.d.ts +4 -0
- package/build/transformer/transforms/reactive-array.js +93 -0
- package/build/transformer/transforms/reactive-object.d.ts +4 -0
- package/build/transformer/transforms/reactive-object.js +164 -0
- package/build/transformer/transforms/reactive-primitives.d.ts +4 -0
- package/build/transformer/transforms/reactive-primitives.js +335 -0
- package/build/transformer/transforms/utilities.d.ts +8 -0
- package/build/transformer/transforms/utilities.js +73 -0
- package/build/types.d.ts +14 -4
- package/package.json +30 -3
- package/readme.md +276 -2
- package/src/constants.ts +1 -1
- package/src/index.ts +1 -1
- package/src/reactive/array.ts +49 -2
- package/src/reactive/index.ts +33 -57
- package/src/system.ts +14 -5
- package/src/transformer/detector.ts +65 -0
- package/src/transformer/index.ts +78 -0
- package/src/transformer/plugins/esbuild.ts +47 -0
- package/src/transformer/plugins/tsc.ts +8 -0
- package/src/transformer/plugins/vite.ts +39 -0
- package/src/transformer/transforms/auto-dispose.ts +191 -0
- package/src/transformer/transforms/reactive-array.ts +143 -0
- package/src/transformer/transforms/reactive-object.ts +253 -0
- package/src/transformer/transforms/reactive-primitives.ts +461 -0
- package/src/transformer/transforms/utilities.ts +119 -0
- package/src/types.ts +24 -5
- package/test/arrays.ts +146 -0
- package/test/effects.ts +168 -0
- package/test/index.ts +8 -0
- package/test/nested.ts +201 -0
- package/test/objects.ts +106 -0
- package/test/primitives.ts +171 -0
- package/test/vite.config.ts +40 -0
- package/build/reactive/object.d.ts +0 -7
- package/build/reactive/object.js +0 -79
- package/src/reactive/object.ts +0 -116
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// Test: Reactive Primitives (Standalone + Object-wrapped)
|
|
2
|
+
import { effect, reactive } from '@esportsplus/reactivity';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// Standalone Signal Primitives
|
|
7
|
+
// =============================================================================
|
|
8
|
+
|
|
9
|
+
console.log('=== Standalone Signal Primitives ===');
|
|
10
|
+
|
|
11
|
+
let count = reactive(0);
|
|
12
|
+
let name = reactive('initial');
|
|
13
|
+
let flag = reactive(true);
|
|
14
|
+
|
|
15
|
+
console.log('Initial count:', count);
|
|
16
|
+
console.log('Initial name:', name);
|
|
17
|
+
console.log('Initial flag:', flag);
|
|
18
|
+
|
|
19
|
+
// Simple assignment
|
|
20
|
+
count = 10;
|
|
21
|
+
name = 'updated';
|
|
22
|
+
flag = false;
|
|
23
|
+
|
|
24
|
+
console.log('After assignment - count:', count);
|
|
25
|
+
console.log('After assignment - name:', name);
|
|
26
|
+
console.log('After assignment - flag:', flag);
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Standalone Computed Primitives
|
|
31
|
+
// =============================================================================
|
|
32
|
+
|
|
33
|
+
console.log('\n=== Standalone Computed Primitives ===');
|
|
34
|
+
|
|
35
|
+
let base = reactive(10);
|
|
36
|
+
let doubled = reactive(() => base * 2);
|
|
37
|
+
let quadrupled = reactive(() => doubled * 2);
|
|
38
|
+
|
|
39
|
+
console.log('base:', base);
|
|
40
|
+
console.log('doubled:', doubled);
|
|
41
|
+
console.log('quadrupled:', quadrupled);
|
|
42
|
+
|
|
43
|
+
base = 5;
|
|
44
|
+
console.log('After base = 5:');
|
|
45
|
+
console.log(' doubled:', doubled);
|
|
46
|
+
console.log(' quadrupled:', quadrupled);
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// Compound Assignments with Standalone Primitives
|
|
51
|
+
// =============================================================================
|
|
52
|
+
|
|
53
|
+
console.log('\n=== Compound Assignments ===');
|
|
54
|
+
|
|
55
|
+
let value = reactive(10);
|
|
56
|
+
|
|
57
|
+
value += 5;
|
|
58
|
+
console.log('After += 5:', value);
|
|
59
|
+
|
|
60
|
+
value -= 3;
|
|
61
|
+
console.log('After -= 3:', value);
|
|
62
|
+
|
|
63
|
+
value *= 2;
|
|
64
|
+
console.log('After *= 2:', value);
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
// =============================================================================
|
|
68
|
+
// Increment/Decrement with Standalone Primitives
|
|
69
|
+
// =============================================================================
|
|
70
|
+
|
|
71
|
+
console.log('\n=== Increment/Decrement ===');
|
|
72
|
+
|
|
73
|
+
let counter = reactive(0);
|
|
74
|
+
|
|
75
|
+
counter++;
|
|
76
|
+
console.log('After counter++:', counter);
|
|
77
|
+
|
|
78
|
+
++counter;
|
|
79
|
+
console.log('After ++counter:', counter);
|
|
80
|
+
|
|
81
|
+
counter--;
|
|
82
|
+
console.log('After counter--:', counter);
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
// =============================================================================
|
|
86
|
+
// Mixed Standalone and Object Primitives
|
|
87
|
+
// =============================================================================
|
|
88
|
+
|
|
89
|
+
console.log('\n=== Mixed Standalone and Object ===');
|
|
90
|
+
|
|
91
|
+
let multiplier = reactive(2);
|
|
92
|
+
|
|
93
|
+
let obj = reactive({
|
|
94
|
+
value: 10,
|
|
95
|
+
scaled: () => obj.value * multiplier
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
console.log('obj.value:', obj.value);
|
|
99
|
+
console.log('obj.scaled:', obj.scaled);
|
|
100
|
+
|
|
101
|
+
multiplier = 3;
|
|
102
|
+
console.log('After multiplier = 3:');
|
|
103
|
+
console.log(' obj.scaled:', obj.scaled);
|
|
104
|
+
|
|
105
|
+
obj.value = 20;
|
|
106
|
+
console.log('After obj.value = 20:');
|
|
107
|
+
console.log(' obj.scaled:', obj.scaled);
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
// =============================================================================
|
|
111
|
+
// Effects with Standalone Primitives
|
|
112
|
+
// =============================================================================
|
|
113
|
+
|
|
114
|
+
console.log('\n=== Effects with Standalone Primitives ===');
|
|
115
|
+
|
|
116
|
+
let effectCount = 0;
|
|
117
|
+
let watched = reactive(0);
|
|
118
|
+
|
|
119
|
+
let cleanup = effect(() => {
|
|
120
|
+
effectCount++;
|
|
121
|
+
console.log(`Effect #${effectCount}: watched = ${watched}`);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
watched = 1;
|
|
125
|
+
watched = 2;
|
|
126
|
+
watched = 3;
|
|
127
|
+
|
|
128
|
+
cleanup();
|
|
129
|
+
|
|
130
|
+
watched = 4; // Should not trigger effect
|
|
131
|
+
console.log('After cleanup, watched set to 4 (no effect should run)');
|
|
132
|
+
console.log('Total effect runs:', effectCount);
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
// =============================================================================
|
|
136
|
+
// String Template Computeds
|
|
137
|
+
// =============================================================================
|
|
138
|
+
|
|
139
|
+
console.log('\n=== String Template Computeds ===');
|
|
140
|
+
|
|
141
|
+
let firstName = reactive('John');
|
|
142
|
+
let lastName = reactive('Doe');
|
|
143
|
+
let fullName = reactive(() => `${firstName} ${lastName}`);
|
|
144
|
+
|
|
145
|
+
console.log('Full name:', fullName);
|
|
146
|
+
|
|
147
|
+
firstName = 'Jane';
|
|
148
|
+
console.log('After firstName = Jane:', fullName);
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
// =============================================================================
|
|
152
|
+
// Object-wrapped Primitives (original tests)
|
|
153
|
+
// =============================================================================
|
|
154
|
+
|
|
155
|
+
console.log('\n=== Object-wrapped Primitives ===');
|
|
156
|
+
|
|
157
|
+
let state = reactive({
|
|
158
|
+
count: 0,
|
|
159
|
+
flag: true,
|
|
160
|
+
name: 'initial'
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
console.log('Initial count:', state.count);
|
|
164
|
+
|
|
165
|
+
state.count = 10;
|
|
166
|
+
state.name = 'updated';
|
|
167
|
+
state.flag = false;
|
|
168
|
+
|
|
169
|
+
console.log('After assignment - count:', state.count);
|
|
170
|
+
console.log('After assignment - name:', state.name);
|
|
171
|
+
console.log('After assignment - flag:', state.flag);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { resolve } from 'path';
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import { plugin as reactivity } from '../build/plugins/vite.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
build: {
|
|
8
|
+
lib: {
|
|
9
|
+
entry: {
|
|
10
|
+
arrays: resolve(__dirname, 'arrays.ts'),
|
|
11
|
+
effects: resolve(__dirname, 'effects.ts'),
|
|
12
|
+
index: resolve(__dirname, 'index.ts'),
|
|
13
|
+
nested: resolve(__dirname, 'nested.ts'),
|
|
14
|
+
objects: resolve(__dirname, 'objects.ts'),
|
|
15
|
+
primitives: resolve(__dirname, 'primitives.ts')
|
|
16
|
+
},
|
|
17
|
+
formats: ['es']
|
|
18
|
+
},
|
|
19
|
+
minify: false,
|
|
20
|
+
outDir: resolve(__dirname, 'build'),
|
|
21
|
+
rollupOptions: {
|
|
22
|
+
external: ['@esportsplus/utilities'],
|
|
23
|
+
output: {
|
|
24
|
+
entryFileNames: '[name].js'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
target: 'esnext'
|
|
28
|
+
},
|
|
29
|
+
plugins: [
|
|
30
|
+
reactivity()
|
|
31
|
+
],
|
|
32
|
+
resolve: {
|
|
33
|
+
alias: {
|
|
34
|
+
'@esportsplus/reactivity/constants': resolve(__dirname, '../src/constants'),
|
|
35
|
+
'@esportsplus/reactivity/reactive/array': resolve(__dirname, '../src/reactive/array'),
|
|
36
|
+
'@esportsplus/reactivity': resolve(__dirname, '../src'),
|
|
37
|
+
'~': resolve(__dirname, '../src')
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
package/build/reactive/object.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { defineProperty, isArray, isPromise } from '@esportsplus/utilities';
|
|
2
|
-
import { computed, dispose, effect, read, root, set, signal } from '../system.js';
|
|
3
|
-
import { REACTIVE_OBJECT } from '../constants.js';
|
|
4
|
-
import { ReactiveArray } from './array.js';
|
|
5
|
-
class ReactiveObject {
|
|
6
|
-
disposers = null;
|
|
7
|
-
constructor(data) {
|
|
8
|
-
let keys = Object.keys(data);
|
|
9
|
-
for (let i = 0, n = keys.length; i < n; ++i) {
|
|
10
|
-
let key = keys[i], value = data[key], type = typeof value;
|
|
11
|
-
if (type === 'function') {
|
|
12
|
-
let node;
|
|
13
|
-
defineProperty(this, key, {
|
|
14
|
-
enumerable: true,
|
|
15
|
-
get: () => {
|
|
16
|
-
if (node === undefined) {
|
|
17
|
-
root(() => {
|
|
18
|
-
node = computed(value);
|
|
19
|
-
if (isPromise(node.value)) {
|
|
20
|
-
let factory = node, version = 0;
|
|
21
|
-
node = signal(undefined);
|
|
22
|
-
(this.disposers ??= []).push(effect(() => {
|
|
23
|
-
let id = ++version;
|
|
24
|
-
read(factory).then((v) => {
|
|
25
|
-
if (id !== version) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
set(node, v);
|
|
29
|
-
});
|
|
30
|
-
}));
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
(this.disposers ??= []).push(() => dispose(node));
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
return read(node);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (value == null || type !== 'object') {
|
|
43
|
-
}
|
|
44
|
-
else if (isArray(value)) {
|
|
45
|
-
let node = new ReactiveArray(...value);
|
|
46
|
-
(this.disposers ??= []).push(() => node.dispose());
|
|
47
|
-
defineProperty(this, key, {
|
|
48
|
-
enumerable: true,
|
|
49
|
-
value: node
|
|
50
|
-
});
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
let node = signal(value);
|
|
54
|
-
defineProperty(this, key, {
|
|
55
|
-
enumerable: true,
|
|
56
|
-
get() {
|
|
57
|
-
return read(node);
|
|
58
|
-
},
|
|
59
|
-
set(v) {
|
|
60
|
-
set(node, v);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
dispose() {
|
|
66
|
-
let disposers = this.disposers, disposer;
|
|
67
|
-
if (!disposers) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
while (disposer = disposers.pop()) {
|
|
71
|
-
disposer();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
Object.defineProperty(ReactiveObject.prototype, REACTIVE_OBJECT, { value: true });
|
|
76
|
-
const isReactiveObject = (value) => {
|
|
77
|
-
return typeof value === 'object' && value !== null && value[REACTIVE_OBJECT] === true;
|
|
78
|
-
};
|
|
79
|
-
export { isReactiveObject, ReactiveObject };
|
package/src/reactive/object.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { defineProperty, isArray, isPromise } from '@esportsplus/utilities';
|
|
2
|
-
import { computed, dispose, effect, read, root, set, signal } from '~/system';
|
|
3
|
-
import { Computed, Signal } from '~/types';
|
|
4
|
-
import { REACTIVE_OBJECT } from '~/constants';
|
|
5
|
-
import { ReactiveArray } from './array';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
9
|
-
private disposers: VoidFunction[] | null = null;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
constructor(data: T) {
|
|
13
|
-
let keys = Object.keys(data);
|
|
14
|
-
|
|
15
|
-
for (let i = 0, n = keys.length; i < n; ++i) {
|
|
16
|
-
let key: keyof T | undefined = keys[i],
|
|
17
|
-
value = data[key],
|
|
18
|
-
type = typeof value;
|
|
19
|
-
|
|
20
|
-
if (type === 'function') {
|
|
21
|
-
let node: Computed<T[typeof key]> | Signal<T[typeof key] | undefined> | undefined;
|
|
22
|
-
|
|
23
|
-
defineProperty(this, key, {
|
|
24
|
-
enumerable: true,
|
|
25
|
-
get: () => {
|
|
26
|
-
if (node === undefined) {
|
|
27
|
-
root(() => {
|
|
28
|
-
node = computed(value as Computed<T[keyof T]>['fn']);
|
|
29
|
-
|
|
30
|
-
if (isPromise(node.value)) {
|
|
31
|
-
let factory = node,
|
|
32
|
-
version = 0;
|
|
33
|
-
|
|
34
|
-
node = signal<T[keyof T] | undefined>(undefined);
|
|
35
|
-
|
|
36
|
-
(this.disposers ??= []).push(
|
|
37
|
-
effect(() => {
|
|
38
|
-
let id = ++version;
|
|
39
|
-
|
|
40
|
-
(read(factory) as Promise<T[keyof T]>).then((v) => {
|
|
41
|
-
if (id !== version) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
set(node as Signal<typeof v>, v);
|
|
46
|
-
});
|
|
47
|
-
})
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
(this.disposers ??= []).push(() => dispose(node as Computed<T[keyof T]>));
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return read(node!);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (value == null || type !== 'object') {
|
|
64
|
-
// Skip isArray when possible
|
|
65
|
-
}
|
|
66
|
-
else if (isArray(value)) {
|
|
67
|
-
let node = new ReactiveArray(...value);
|
|
68
|
-
|
|
69
|
-
(this.disposers ??= []).push( () => node.dispose() );
|
|
70
|
-
|
|
71
|
-
defineProperty(this, key, {
|
|
72
|
-
enumerable: true,
|
|
73
|
-
value: node
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let node = signal(value);
|
|
80
|
-
|
|
81
|
-
defineProperty(this, key, {
|
|
82
|
-
enumerable: true,
|
|
83
|
-
get() {
|
|
84
|
-
return read(node);
|
|
85
|
-
},
|
|
86
|
-
set(v: typeof value) {
|
|
87
|
-
set(node, v);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
dispose() {
|
|
95
|
-
let disposers = this.disposers,
|
|
96
|
-
disposer;
|
|
97
|
-
|
|
98
|
-
if (!disposers) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
while (disposer = disposers.pop()) {
|
|
103
|
-
disposer();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
Object.defineProperty(ReactiveObject.prototype, REACTIVE_OBJECT, { value: true });
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const isReactiveObject = (value: any): value is ReactiveObject<any> => {
|
|
112
|
-
return typeof value === 'object' && value !== null && value[REACTIVE_OBJECT] === true;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
export { isReactiveObject, ReactiveObject };
|