@esportsplus/reactivity 0.22.1 → 0.23.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 (59) hide show
  1. package/.github/workflows/bump.yml +2 -2
  2. package/.github/workflows/dependabot.yml +1 -1
  3. package/.github/workflows/publish.yml +2 -2
  4. package/build/index.d.ts +1 -1
  5. package/build/index.js +1 -1
  6. package/build/reactive/array.d.ts +3 -0
  7. package/build/reactive/array.js +32 -2
  8. package/build/reactive/index.d.ts +17 -14
  9. package/build/reactive/index.js +7 -25
  10. package/build/system.js +1 -1
  11. package/build/transformer/core/detector.d.ts +2 -0
  12. package/build/transformer/core/detector.js +6 -0
  13. package/build/transformer/core/index.d.ts +10 -0
  14. package/build/transformer/core/index.js +55 -0
  15. package/build/transformer/core/transforms/auto-dispose.d.ts +3 -0
  16. package/build/transformer/core/transforms/auto-dispose.js +116 -0
  17. package/build/transformer/core/transforms/reactive-array.d.ts +4 -0
  18. package/build/transformer/core/transforms/reactive-array.js +89 -0
  19. package/build/transformer/core/transforms/reactive-object.d.ts +4 -0
  20. package/build/transformer/core/transforms/reactive-object.js +155 -0
  21. package/build/transformer/core/transforms/reactive-primitives.d.ts +4 -0
  22. package/build/transformer/core/transforms/reactive-primitives.js +325 -0
  23. package/build/transformer/core/transforms/utilities.d.ts +9 -0
  24. package/build/transformer/core/transforms/utilities.js +57 -0
  25. package/build/transformer/plugins/esbuild.d.ts +5 -0
  26. package/build/transformer/plugins/esbuild.js +30 -0
  27. package/build/transformer/plugins/tsc.d.ts +3 -0
  28. package/build/transformer/plugins/tsc.js +4 -0
  29. package/build/transformer/plugins/vite.d.ts +5 -0
  30. package/build/transformer/plugins/vite.js +28 -0
  31. package/build/types.d.ts +14 -4
  32. package/package.json +34 -3
  33. package/readme.md +276 -2
  34. package/src/constants.ts +1 -1
  35. package/src/index.ts +1 -1
  36. package/src/reactive/array.ts +49 -2
  37. package/src/reactive/index.ts +33 -57
  38. package/src/system.ts +14 -5
  39. package/src/transformer/core/detector.ts +12 -0
  40. package/src/transformer/core/index.ts +82 -0
  41. package/src/transformer/core/transforms/auto-dispose.ts +194 -0
  42. package/src/transformer/core/transforms/reactive-array.ts +140 -0
  43. package/src/transformer/core/transforms/reactive-object.ts +244 -0
  44. package/src/transformer/core/transforms/reactive-primitives.ts +459 -0
  45. package/src/transformer/core/transforms/utilities.ts +95 -0
  46. package/src/transformer/plugins/esbuild.ts +46 -0
  47. package/src/transformer/plugins/tsc.ts +8 -0
  48. package/src/transformer/plugins/vite.ts +41 -0
  49. package/src/types.ts +24 -5
  50. package/test/arrays.ts +146 -0
  51. package/test/effects.ts +168 -0
  52. package/test/index.ts +8 -0
  53. package/test/nested.ts +201 -0
  54. package/test/objects.ts +106 -0
  55. package/test/primitives.ts +171 -0
  56. package/test/vite.config.ts +40 -0
  57. package/build/reactive/object.d.ts +0 -7
  58. package/build/reactive/object.js +0 -79
  59. 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
+ });
@@ -1,7 +0,0 @@
1
- declare class ReactiveObject<T extends Record<PropertyKey, unknown>> {
2
- private disposers;
3
- constructor(data: T);
4
- dispose(): void;
5
- }
6
- declare const isReactiveObject: (value: any) => value is ReactiveObject<any>;
7
- export { isReactiveObject, ReactiveObject };
@@ -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 };
@@ -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 };