rask-ui 0.20.1 → 0.20.3

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 (114) hide show
  1. package/dist/asyncState.d.ts +16 -0
  2. package/dist/asyncState.d.ts.map +1 -0
  3. package/dist/asyncState.js +24 -0
  4. package/dist/compiler.d.ts +2 -0
  5. package/dist/compiler.d.ts.map +1 -0
  6. package/dist/compiler.js +1 -0
  7. package/dist/component.d.ts +1 -1
  8. package/dist/component.d.ts.map +1 -1
  9. package/dist/component.js +15 -2
  10. package/dist/context.d.ts +5 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +29 -0
  13. package/dist/createAsync.test.d.ts +2 -0
  14. package/dist/createAsync.test.d.ts.map +1 -0
  15. package/dist/createAsync.test.js +110 -0
  16. package/dist/createMutation.test.d.ts +2 -0
  17. package/dist/createMutation.test.d.ts.map +1 -0
  18. package/dist/createMutation.test.js +168 -0
  19. package/dist/createQuery.test.d.ts +2 -0
  20. package/dist/createQuery.test.d.ts.map +1 -0
  21. package/dist/createQuery.test.js +156 -0
  22. package/dist/createRef.d.ts +6 -0
  23. package/dist/createRef.d.ts.map +1 -0
  24. package/dist/createRef.js +8 -0
  25. package/dist/createState.d.ts +0 -2
  26. package/dist/createState.d.ts.map +1 -1
  27. package/dist/createState.js +5 -40
  28. package/dist/createState.test.d.ts.map +1 -0
  29. package/dist/createState.test.js +111 -0
  30. package/dist/createView.d.ts +44 -18
  31. package/dist/createView.d.ts.map +1 -1
  32. package/dist/createView.js +48 -57
  33. package/dist/createView.test.d.ts.map +1 -0
  34. package/dist/{tests/createView.test.js → createView.test.js} +40 -40
  35. package/dist/error.d.ts +14 -3
  36. package/dist/error.d.ts.map +1 -1
  37. package/dist/error.js +15 -14
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +2 -2
  41. package/dist/jsx.d.ts +256 -10
  42. package/dist/observation.test.d.ts.map +1 -0
  43. package/dist/observation.test.js +150 -0
  44. package/dist/plugin.js +1 -1
  45. package/dist/suspense.d.ts +25 -0
  46. package/dist/suspense.d.ts.map +1 -0
  47. package/dist/suspense.js +97 -0
  48. package/dist/test-setup.d.ts +16 -0
  49. package/dist/test-setup.d.ts.map +1 -0
  50. package/dist/test-setup.js +40 -0
  51. package/dist/test.d.ts +2 -0
  52. package/dist/test.d.ts.map +1 -0
  53. package/dist/test.js +24 -0
  54. package/dist/types.d.ts +20 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +1 -0
  57. package/package.json +5 -1
  58. package/swc-plugin/target/wasm32-wasip1/release/swc_plugin_rask_component.wasm +0 -0
  59. package/dist/createComputed.d.ts +0 -4
  60. package/dist/createComputed.d.ts.map +0 -1
  61. package/dist/createComputed.js +0 -69
  62. package/dist/createEffect.d.ts +0 -2
  63. package/dist/createEffect.d.ts.map +0 -1
  64. package/dist/createEffect.js +0 -29
  65. package/dist/createRouter.d.ts +0 -8
  66. package/dist/createRouter.d.ts.map +0 -1
  67. package/dist/createRouter.js +0 -27
  68. package/dist/createTask.d.ts +0 -31
  69. package/dist/createTask.d.ts.map +0 -1
  70. package/dist/createTask.js +0 -79
  71. package/dist/patchInferno.d.ts +0 -6
  72. package/dist/patchInferno.d.ts.map +0 -1
  73. package/dist/patchInferno.js +0 -53
  74. package/dist/scheduler.d.ts +0 -4
  75. package/dist/scheduler.d.ts.map +0 -1
  76. package/dist/scheduler.js +0 -107
  77. package/dist/tests/batch.test.d.ts +0 -2
  78. package/dist/tests/batch.test.d.ts.map +0 -1
  79. package/dist/tests/batch.test.js +0 -244
  80. package/dist/tests/createComputed.test.d.ts +0 -2
  81. package/dist/tests/createComputed.test.d.ts.map +0 -1
  82. package/dist/tests/createComputed.test.js +0 -257
  83. package/dist/tests/createContext.test.d.ts +0 -2
  84. package/dist/tests/createContext.test.d.ts.map +0 -1
  85. package/dist/tests/createContext.test.js +0 -136
  86. package/dist/tests/createEffect.test.d.ts +0 -2
  87. package/dist/tests/createEffect.test.d.ts.map +0 -1
  88. package/dist/tests/createEffect.test.js +0 -467
  89. package/dist/tests/createState.test.d.ts.map +0 -1
  90. package/dist/tests/createState.test.js +0 -144
  91. package/dist/tests/createTask.test.d.ts +0 -2
  92. package/dist/tests/createTask.test.d.ts.map +0 -1
  93. package/dist/tests/createTask.test.js +0 -322
  94. package/dist/tests/createView.test.d.ts.map +0 -1
  95. package/dist/tests/error.test.d.ts +0 -2
  96. package/dist/tests/error.test.d.ts.map +0 -1
  97. package/dist/tests/error.test.js +0 -168
  98. package/dist/tests/observation.test.d.ts.map +0 -1
  99. package/dist/tests/observation.test.js +0 -341
  100. package/dist/useComputed.d.ts +0 -5
  101. package/dist/useComputed.d.ts.map +0 -1
  102. package/dist/useComputed.js +0 -69
  103. package/dist/useQuery.d.ts +0 -25
  104. package/dist/useQuery.d.ts.map +0 -1
  105. package/dist/useQuery.js +0 -25
  106. package/dist/useSuspendAsync.d.ts +0 -18
  107. package/dist/useSuspendAsync.d.ts.map +0 -1
  108. package/dist/useSuspendAsync.js +0 -37
  109. package/dist/useTask.d.ts +0 -25
  110. package/dist/useTask.d.ts.map +0 -1
  111. package/dist/useTask.js +0 -70
  112. /package/dist/{tests/createState.test.d.ts → createState.test.d.ts} +0 -0
  113. /package/dist/{tests/createView.test.d.ts → createView.test.d.ts} +0 -0
  114. /package/dist/{tests/observation.test.d.ts → observation.test.d.ts} +0 -0
@@ -1,9 +1,4 @@
1
- import { getCurrentComponent } from "./component";
2
- import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
3
1
  import { getCurrentObserver, Signal } from "./observation";
4
- export function assignState(state, newState) {
5
- return Object.assign(state, newState);
6
- }
7
2
  /**
8
3
  * Creates a reactive state object that tracks property access and notifies observers on changes.
9
4
  *
@@ -29,14 +24,11 @@ export function assignState(state, newState) {
29
24
  * @returns A reactive proxy of the state object
30
25
  */
31
26
  export function createState(state) {
32
- if (getCurrentComponent()?.isRendering) {
33
- throw new Error("createState cannot be called during render. Call it in component setup or globally.");
34
- }
35
- return getProxy(state, {});
27
+ return getProxy(state);
36
28
  }
37
29
  const proxyCache = new WeakMap();
38
- export const PROXY_MARKER = Symbol("isProxy");
39
- function getProxy(value, notifyInspectorRef) {
30
+ const PROXY_MARKER = Symbol("isProxy");
31
+ function getProxy(value) {
40
32
  // Check if already a proxy to avoid double-wrapping
41
33
  if (PROXY_MARKER in value) {
42
34
  return value;
@@ -51,9 +43,6 @@ function getProxy(value, notifyInspectorRef) {
51
43
  if (key === PROXY_MARKER) {
52
44
  return true;
53
45
  }
54
- if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
55
- return true;
56
- }
57
46
  return Reflect.has(target, key);
58
47
  },
59
48
  get(target, key) {
@@ -61,9 +50,6 @@ function getProxy(value, notifyInspectorRef) {
61
50
  if (key === PROXY_MARKER) {
62
51
  return true;
63
52
  }
64
- if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
65
- return !notifyInspectorRef.current;
66
- }
67
53
  const value = Reflect.get(target, key);
68
54
  if (typeof key === "symbol" || typeof value === "function") {
69
55
  return value;
@@ -75,26 +61,11 @@ function getProxy(value, notifyInspectorRef) {
75
61
  }
76
62
  if (Array.isArray(value) ||
77
63
  (typeof value === "object" && value !== null)) {
78
- return getProxy(value, INSPECTOR_ENABLED && notifyInspectorRef.current
79
- ? {
80
- current: {
81
- notify: notifyInspectorRef.current.notify,
82
- path: notifyInspectorRef.current.path.concat(key),
83
- },
84
- }
85
- : notifyInspectorRef);
64
+ return getProxy(value);
86
65
  }
87
66
  return value;
88
67
  },
89
68
  set(target, key, newValue) {
90
- if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
91
- Object.defineProperty(notifyInspectorRef, "current", {
92
- get() {
93
- return newValue.current;
94
- },
95
- });
96
- return Reflect.set(target, key, newValue);
97
- }
98
69
  if (typeof key === "symbol") {
99
70
  return Reflect.set(target, key, newValue);
100
71
  }
@@ -102,16 +73,10 @@ function getProxy(value, notifyInspectorRef) {
102
73
  const setResult = Reflect.set(target, key, newValue);
103
74
  // We only notify if actual change, though array length actually updates under the hood
104
75
  if (newValue !== oldValue || (Array.isArray(value) && key === "length")) {
76
+ console.log("WTF", key, newValue);
105
77
  const signal = signals[key];
106
78
  signal?.notify();
107
79
  }
108
- if (INSPECTOR_ENABLED) {
109
- notifyInspectorRef.current?.notify({
110
- type: "mutation",
111
- path: notifyInspectorRef.current.path,
112
- value: newValue,
113
- });
114
- }
115
80
  return setResult;
116
81
  },
117
82
  deleteProperty(target, key) {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createState.test.d.ts","sourceRoot":"","sources":["../src/createState.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,111 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createState } from './createState';
3
+ import { Observer } from './observation';
4
+ describe('createState', () => {
5
+ it('should create a reactive proxy from an object', () => {
6
+ const state = createState({ count: 0 });
7
+ expect(state.count).toBe(0);
8
+ });
9
+ it('should allow mutations', () => {
10
+ const state = createState({ count: 0 });
11
+ state.count = 5;
12
+ expect(state.count).toBe(5);
13
+ });
14
+ it('should return the same proxy for the same object', () => {
15
+ const obj = { count: 0 };
16
+ const proxy1 = createState(obj);
17
+ const proxy2 = createState(obj);
18
+ expect(proxy1).toBe(proxy2);
19
+ });
20
+ it('should create nested proxies for nested objects', () => {
21
+ const state = createState({ user: { name: 'Alice', age: 30 } });
22
+ state.user.name = 'Bob';
23
+ expect(state.user.name).toBe('Bob');
24
+ });
25
+ it('should handle arrays reactively', () => {
26
+ const state = createState({ items: [1, 2, 3] });
27
+ state.items.push(4);
28
+ expect(state.items).toEqual([1, 2, 3, 4]);
29
+ });
30
+ it('should track property access in observers', () => {
31
+ const state = createState({ count: 0 });
32
+ let renderCount = 0;
33
+ const observer = new Observer(() => {
34
+ renderCount++;
35
+ });
36
+ const dispose = observer.observe();
37
+ state.count; // Access property to track it
38
+ dispose();
39
+ expect(renderCount).toBe(0);
40
+ // Mutate after observation setup
41
+ const dispose2 = observer.observe();
42
+ const value = state.count; // Track
43
+ dispose2(); // Stop observing, subscriptions are now active
44
+ state.count = 1;
45
+ // Wait for microtask
46
+ return new Promise((resolve) => {
47
+ queueMicrotask(() => {
48
+ expect(renderCount).toBeGreaterThan(0);
49
+ resolve(undefined);
50
+ });
51
+ });
52
+ });
53
+ it('should handle property deletion', () => {
54
+ const state = createState({ count: 0, temp: 'value' });
55
+ delete state.temp;
56
+ expect(state.temp).toBeUndefined();
57
+ expect('temp' in state).toBe(false);
58
+ });
59
+ it('should not create proxies for functions', () => {
60
+ const fn = () => 'hello';
61
+ const state = createState({ method: fn });
62
+ expect(state.method).toBe(fn);
63
+ expect(state.method()).toBe('hello');
64
+ });
65
+ it('should handle symbol properties', () => {
66
+ const sym = Symbol('test');
67
+ const state = createState({ [sym]: 'value' });
68
+ expect(state[sym]).toBe('value');
69
+ });
70
+ it('should notify observers only on actual changes', () => {
71
+ const state = createState({ count: 0 });
72
+ let notifyCount = 0;
73
+ const observer = new Observer(() => {
74
+ notifyCount++;
75
+ });
76
+ const dispose = observer.observe();
77
+ state.count; // Track
78
+ dispose();
79
+ state.count = 0; // Same value - should still notify per current implementation
80
+ state.count = 0;
81
+ return new Promise((resolve) => {
82
+ queueMicrotask(() => {
83
+ // The implementation notifies even for same value, except for optimization cases
84
+ observer.dispose();
85
+ resolve(undefined);
86
+ });
87
+ });
88
+ });
89
+ it('should handle deeply nested objects', () => {
90
+ const state = createState({
91
+ level1: {
92
+ level2: {
93
+ level3: {
94
+ value: 'deep',
95
+ },
96
+ },
97
+ },
98
+ });
99
+ state.level1.level2.level3.value = 'modified';
100
+ expect(state.level1.level2.level3.value).toBe('modified');
101
+ });
102
+ it('should handle array mutations correctly', () => {
103
+ const state = createState({ items: [1, 2, 3] });
104
+ state.items.pop();
105
+ expect(state.items).toEqual([1, 2]);
106
+ state.items.unshift(0);
107
+ expect(state.items).toEqual([0, 1, 2]);
108
+ state.items.splice(1, 1, 99);
109
+ expect(state.items).toEqual([0, 99, 2]);
110
+ });
111
+ });
@@ -1,28 +1,54 @@
1
- type Simplify<T> = T extends any ? {
1
+ type Simplify<T> = {
2
2
  [K in keyof T]: T[K];
3
- } : never;
4
- type UndefinedKeys<T> = {
5
- [K in keyof T]-?: [T[K]] extends [undefined] ? K : never;
6
- }[keyof T];
7
- type MergeTwo<A extends object, B extends object> = A extends any ? Simplify<Omit<A, keyof B> & Omit<B, UndefinedKeys<B>>> : never;
3
+ } & {};
4
+ type MergeTwo<A extends object, B extends object> = Simplify<Omit<A, keyof B> & B>;
8
5
  type MergeMany<T extends readonly object[]> = T extends [
9
6
  infer H extends object,
10
7
  ...infer R extends object[]
11
- ] ? MergeManyAcc<H, R> : {};
12
- type MergeManyAcc<Acc extends object, Rest extends object[]> = Rest extends [
13
- infer H extends object,
14
- ...infer R extends object[]
15
- ] ? MergeManyAcc<MergeTwo<Acc, H>, R> : Acc;
8
+ ] ? MergeTwo<H, MergeMany<R>> : {};
16
9
  /**
17
- * Creates a view that merges multiple objects (reactive or not) into a single
18
- * object while maintaining reactivity through getters. Properties from later
19
- * arguments override earlier ones.
10
+ * Creates a view that merges multiple objects (reactive or not) into a single object while
11
+ * maintaining reactivity through getters. Properties from later arguments override earlier ones.
12
+ *
13
+ * @warning **Do not destructure the returned view object!** Destructuring breaks reactivity
14
+ * because it extracts plain values instead of maintaining getter access. This is the same rule
15
+ * as other reactive primitives.
16
+ *
17
+ * @example
18
+ * // ❌ Bad - destructuring loses reactivity
19
+ * function Component() {
20
+ * const state = createState({ count: 0 });
21
+ * const helpers = { increment: () => state.count++ };
22
+ * const view = createView(state, helpers);
23
+ * const { count, increment } = view; // Don't do this!
24
+ * return () => <button onClick={increment}>{count}</button>; // Won't update!
25
+ * }
26
+ *
27
+ * // ✅ Good - access properties directly in render
28
+ * function Component() {
29
+ * const state = createState({ count: 0 });
30
+ * const helpers = { increment: () => state.count++ };
31
+ * const view = createView(state, helpers);
32
+ * return () => <button onClick={view.increment}>{view.count}</button>; // Reactive!
33
+ * }
34
+ *
35
+ * @example
36
+ * // Merge multiple reactive objects
37
+ * const state = createState({ count: 0 });
38
+ * const user = createState({ name: "Alice" });
39
+ * const view = createView(state, user);
40
+ * // view has both count and name properties, maintaining reactivity
41
+ *
42
+ * @example
43
+ * // Later arguments override earlier ones
44
+ * const a = { x: 1, y: 2 };
45
+ * const b = { y: 3, z: 4 };
46
+ * const view = createView(a, b);
47
+ * // view.x === 1, view.y === 3, view.z === 4
20
48
  *
21
- * ⚠️ Do not destructure the returned view object; always read properties
22
- * directly from the view to preserve reactivity.
49
+ * @param args - Objects to merge (reactive or plain objects)
50
+ * @returns A view object with getters for all properties, maintaining reactivity
23
51
  */
24
- export declare function createView<A extends object>(a: A): A;
25
- export declare function createView<A extends object, B extends object>(a: A, b: B): MergeTwo<A, B>;
26
52
  export declare function createView<T extends readonly object[]>(...args: T): MergeMany<T>;
27
53
  export {};
28
54
  //# sourceMappingURL=createView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createView.d.ts","sourceRoot":"","sources":["../src/createView.ts"],"names":[],"mappings":"AAGA,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,KAAK,CAAC;AAEpE,KAAK,aAAa,CAAC,CAAC,IAAI;KACrB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK;CACzD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,GAC7D,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACtD,KAAK,CAAC;AAEV,KAAK,SAAS,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI,CAAC,SAAS;IACtD,MAAM,CAAC,SAAS,MAAM;IACtB,GAAG,MAAM,CAAC,SAAS,MAAM,EAAE;CAC5B,GACG,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAClB,EAAE,CAAC;AAEP,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,EAAE,IAAI,SAAS,MAAM,EAAE,IAAI,IAAI,SAAS;IAC1E,MAAM,CAAC,SAAS,MAAM;IACtB,GAAG,MAAM,CAAC,SAAS,MAAM,EAAE;CAC5B,GACG,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,GAAG,CAAC;AAER;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AACtD,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAC3D,CAAC,EAAE,CAAC,EACJ,CAAC,EAAE,CAAC,GACH,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAClB,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACpD,GAAG,IAAI,EAAE,CAAC,GACT,SAAS,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"createView.d.ts","sourceRoot":"","sources":["../src/createView.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAEjD,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,QAAQ,CAC1D,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CACrB,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI,CAAC,SAAS;IACtD,MAAM,CAAC,SAAS,MAAM;IACtB,GAAG,MAAM,CAAC,SAAS,MAAM,EAAE;CAC5B,GACG,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,GACzB,EAAE,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACpD,GAAG,IAAI,EAAE,CAAC,GACT,SAAS,CAAC,CAAC,CAAC,CA0Bd"}
@@ -1,77 +1,68 @@
1
- import { getCurrentComponent } from "./component";
2
- import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
1
+ /**
2
+ * Creates a view that merges multiple objects (reactive or not) into a single object while
3
+ * maintaining reactivity through getters. Properties from later arguments override earlier ones.
4
+ *
5
+ * @warning **Do not destructure the returned view object!** Destructuring breaks reactivity
6
+ * because it extracts plain values instead of maintaining getter access. This is the same rule
7
+ * as other reactive primitives.
8
+ *
9
+ * @example
10
+ * // ❌ Bad - destructuring loses reactivity
11
+ * function Component() {
12
+ * const state = createState({ count: 0 });
13
+ * const helpers = { increment: () => state.count++ };
14
+ * const view = createView(state, helpers);
15
+ * const { count, increment } = view; // Don't do this!
16
+ * return () => <button onClick={increment}>{count}</button>; // Won't update!
17
+ * }
18
+ *
19
+ * // ✅ Good - access properties directly in render
20
+ * function Component() {
21
+ * const state = createState({ count: 0 });
22
+ * const helpers = { increment: () => state.count++ };
23
+ * const view = createView(state, helpers);
24
+ * return () => <button onClick={view.increment}>{view.count}</button>; // Reactive!
25
+ * }
26
+ *
27
+ * @example
28
+ * // Merge multiple reactive objects
29
+ * const state = createState({ count: 0 });
30
+ * const user = createState({ name: "Alice" });
31
+ * const view = createView(state, user);
32
+ * // view has both count and name properties, maintaining reactivity
33
+ *
34
+ * @example
35
+ * // Later arguments override earlier ones
36
+ * const a = { x: 1, y: 2 };
37
+ * const b = { y: 3, z: 4 };
38
+ * const view = createView(a, b);
39
+ * // view.x === 1, view.y === 3, view.z === 4
40
+ *
41
+ * @param args - Objects to merge (reactive or plain objects)
42
+ * @returns A view object with getters for all properties, maintaining reactivity
43
+ */
3
44
  export function createView(...args) {
4
- if (!getCurrentComponent()) {
5
- throw new Error("Only use createView in component setup");
6
- }
7
45
  const result = {};
8
46
  const seen = new Set();
9
- let notifyInspectorRef = {};
10
47
  for (let i = args.length - 1; i >= 0; i--) {
11
48
  const src = args[i];
12
- if (!src)
13
- continue;
14
- if (INSPECTOR_ENABLED && src[INSPECT_MARKER]) {
15
- src[INSPECT_MARKER] = notifyInspectorRef;
16
- }
17
- // Mimic Object.assign: only enumerable own property keys
49
+ // mimic Object.assign: only enumerable own property keys
18
50
  for (const key of Reflect.ownKeys(src)) {
19
51
  if (seen.has(key))
20
52
  continue;
21
53
  const desc = Object.getOwnPropertyDescriptor(src, key);
22
54
  if (!desc || !desc.enumerable)
23
55
  continue;
56
+ // Capture the current source for this key (last write wins).
24
57
  Object.defineProperty(result, key, {
25
58
  enumerable: true,
26
59
  configurable: true,
27
- get: () => {
28
- const value = src[key];
29
- if (!INSPECTOR_ENABLED || !notifyInspectorRef.current) {
30
- return value;
31
- }
32
- // Propagate inspector marker into nested observables
33
- if (value?.[INSPECT_MARKER]) {
34
- value[INSPECT_MARKER] = {
35
- current: {
36
- notify: notifyInspectorRef.current.notify,
37
- path: notifyInspectorRef.current.path.concat(key),
38
- },
39
- };
40
- }
41
- else if (typeof value === "function") {
42
- // Wrap actions to notify inspector
43
- return (...params) => {
44
- notifyInspectorRef.current.notify({
45
- type: "action",
46
- path: notifyInspectorRef.current.path.concat(key),
47
- params,
48
- });
49
- return value(...params);
50
- };
51
- }
52
- return value;
53
- },
60
+ get: () => src[key],
61
+ // Optional write-through (commented out by default):
62
+ // set: (value) => { (src as any)[key as any] = value; },
54
63
  });
55
64
  seen.add(key);
56
65
  }
57
66
  }
58
- if (INSPECTOR_ENABLED) {
59
- Object.defineProperty(result, INSPECT_MARKER, {
60
- enumerable: false,
61
- configurable: false,
62
- get() {
63
- return !notifyInspectorRef.current;
64
- },
65
- set: (value) => {
66
- Object.defineProperty(notifyInspectorRef, "current", {
67
- configurable: true,
68
- get() {
69
- return value.current;
70
- },
71
- });
72
- },
73
- });
74
- }
75
- // The overload signatures expose a precise type; this is the shared impl.
76
67
  return result;
77
68
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createView.test.d.ts","sourceRoot":"","sources":["../src/createView.test.ts"],"names":[],"mappings":""}
@@ -1,9 +1,9 @@
1
- import { describe, it, expect } from "vitest";
2
- import { createView } from "../createView";
3
- import { createState } from "../createState";
4
- import { Observer } from "../observation";
5
- describe("createView", () => {
6
- it("should merge two plain objects", () => {
1
+ import { describe, it, expect } from 'vitest';
2
+ import { createView } from './createView';
3
+ import { createState } from './createState';
4
+ import { Observer } from './observation';
5
+ describe('createView', () => {
6
+ it('should merge two plain objects', () => {
7
7
  const a = { x: 1, y: 2 };
8
8
  const b = { z: 3 };
9
9
  const view = createView(a, b);
@@ -11,7 +11,7 @@ describe("createView", () => {
11
11
  expect(view.y).toBe(2);
12
12
  expect(view.z).toBe(3);
13
13
  });
14
- it("should allow later arguments to override earlier ones", () => {
14
+ it('should allow later arguments to override earlier ones', () => {
15
15
  const a = { x: 1, y: 2 };
16
16
  const b = { y: 3, z: 4 };
17
17
  const view = createView(a, b);
@@ -19,7 +19,7 @@ describe("createView", () => {
19
19
  expect(view.y).toBe(3); // b.y overrides a.y
20
20
  expect(view.z).toBe(4);
21
21
  });
22
- it("should maintain reactivity with reactive objects", async () => {
22
+ it('should maintain reactivity with reactive objects', async () => {
23
23
  const state = createState({ count: 0 });
24
24
  const view = createView(state);
25
25
  let renderCount = 0;
@@ -42,7 +42,7 @@ describe("createView", () => {
42
42
  });
43
43
  });
44
44
  });
45
- it("should merge reactive and plain objects while maintaining reactivity", () => {
45
+ it('should merge reactive and plain objects while maintaining reactivity', () => {
46
46
  const state = createState({ count: 0 });
47
47
  const helpers = {
48
48
  increment() {
@@ -54,36 +54,36 @@ describe("createView", () => {
54
54
  };
55
55
  const view = createView(state, helpers);
56
56
  expect(view.count).toBe(0);
57
- expect(typeof view.increment).toBe("function");
58
- expect(typeof view.decrement).toBe("function");
57
+ expect(typeof view.increment).toBe('function');
58
+ expect(typeof view.decrement).toBe('function');
59
59
  view.increment();
60
60
  expect(view.count).toBe(1);
61
61
  view.decrement();
62
62
  expect(view.count).toBe(0);
63
63
  });
64
- it("should merge multiple reactive objects", () => {
64
+ it('should merge multiple reactive objects', () => {
65
65
  const state1 = createState({ count: 0 });
66
- const state2 = createState({ name: "Alice" });
66
+ const state2 = createState({ name: 'Alice' });
67
67
  const state3 = createState({ age: 25 });
68
68
  const view = createView(state1, state2, state3);
69
69
  expect(view.count).toBe(0);
70
- expect(view.name).toBe("Alice");
70
+ expect(view.name).toBe('Alice');
71
71
  expect(view.age).toBe(25);
72
72
  state1.count = 10;
73
- state2.name = "Bob";
73
+ state2.name = 'Bob';
74
74
  state3.age = 30;
75
75
  expect(view.count).toBe(10);
76
- expect(view.name).toBe("Bob");
76
+ expect(view.name).toBe('Bob');
77
77
  expect(view.age).toBe(30);
78
78
  });
79
- it("should reflect changes in source objects", () => {
79
+ it('should reflect changes in source objects', () => {
80
80
  const source = { x: 1 };
81
81
  const view = createView(source);
82
82
  expect(view.x).toBe(1);
83
83
  source.x = 2;
84
84
  expect(view.x).toBe(2);
85
85
  });
86
- it("should handle property override order correctly", () => {
86
+ it('should handle property override order correctly', () => {
87
87
  const a = { x: 1, y: 2, z: 3 };
88
88
  const b = { y: 20 };
89
89
  const c = { z: 30 };
@@ -92,9 +92,9 @@ describe("createView", () => {
92
92
  expect(view.y).toBe(20); // From b (overrides a)
93
93
  expect(view.z).toBe(30); // From c (overrides a)
94
94
  });
95
- it("should only include enumerable properties", () => {
95
+ it('should only include enumerable properties', () => {
96
96
  const obj = { x: 1 };
97
- Object.defineProperty(obj, "hidden", {
97
+ Object.defineProperty(obj, 'hidden', {
98
98
  value: 42,
99
99
  enumerable: false,
100
100
  });
@@ -102,15 +102,15 @@ describe("createView", () => {
102
102
  expect(view.x).toBe(1);
103
103
  expect(view.hidden).toBeUndefined();
104
104
  });
105
- it("should handle symbol keys", () => {
106
- const sym = Symbol("test");
107
- const obj = { x: 1, [sym]: "symbol value" };
105
+ it('should handle symbol keys', () => {
106
+ const sym = Symbol('test');
107
+ const obj = { x: 1, [sym]: 'symbol value' };
108
108
  const view = createView(obj);
109
109
  expect(view.x).toBe(1);
110
- expect(view[sym]).toBe("symbol value");
110
+ expect(view[sym]).toBe('symbol value');
111
111
  });
112
- it("should track dependencies for each property independently", async () => {
113
- const state = createState({ count: 0, name: "Alice" });
112
+ it('should track dependencies for each property independently', async () => {
113
+ const state = createState({ count: 0, name: 'Alice' });
114
114
  const view = createView(state);
115
115
  let countRenderCount = 0;
116
116
  let nameRenderCount = 0;
@@ -131,7 +131,7 @@ describe("createView", () => {
131
131
  });
132
132
  });
133
133
  // Change name - should NOT trigger (not tracked)
134
- state.name = "Bob";
134
+ state.name = 'Bob';
135
135
  await new Promise((resolve) => {
136
136
  queueMicrotask(() => {
137
137
  expect(countRenderCount).toBe(1); // Still 1
@@ -147,7 +147,7 @@ describe("createView", () => {
147
147
  dispose2();
148
148
  expect(nameRenderCount).toBe(0);
149
149
  // Change name - should trigger name observer
150
- state.name = "Charlie";
150
+ state.name = 'Charlie';
151
151
  await new Promise((resolve) => {
152
152
  queueMicrotask(() => {
153
153
  expect(nameRenderCount).toBe(1);
@@ -155,25 +155,25 @@ describe("createView", () => {
155
155
  });
156
156
  });
157
157
  });
158
- it("should return the same value type as source", () => {
158
+ it('should return the same value type as source', () => {
159
159
  const obj = { nums: [1, 2, 3], nested: { x: 1 } };
160
160
  const view = createView(obj);
161
161
  expect(Array.isArray(view.nums)).toBe(true);
162
162
  expect(view.nums).toEqual([1, 2, 3]);
163
- expect(typeof view.nested).toBe("object");
163
+ expect(typeof view.nested).toBe('object');
164
164
  expect(view.nested.x).toBe(1);
165
165
  });
166
- it("should handle empty merge", () => {
166
+ it('should handle empty merge', () => {
167
167
  const view = createView({});
168
168
  expect(Object.keys(view).length).toBe(0);
169
169
  });
170
- it("should merge single object", () => {
170
+ it('should merge single object', () => {
171
171
  const obj = { x: 1, y: 2 };
172
172
  const view = createView(obj);
173
173
  expect(view.x).toBe(1);
174
174
  expect(view.y).toBe(2);
175
175
  });
176
- it("should maintain function context", () => {
176
+ it('should maintain function context', () => {
177
177
  const state = createState({ count: 0 });
178
178
  const methods = {
179
179
  increment() {
@@ -186,18 +186,18 @@ describe("createView", () => {
186
186
  expect(view.count).toBe(1);
187
187
  expect(state.count).toBe(1);
188
188
  });
189
- it("should work with reactive state and computed-like patterns", () => {
190
- const state = createState({ firstName: "John", lastName: "Doe" });
189
+ it('should work with reactive state and computed-like patterns', () => {
190
+ const state = createState({ firstName: 'John', lastName: 'Doe' });
191
191
  const computed = {
192
192
  get fullName() {
193
193
  return `${state.firstName} ${state.lastName}`;
194
194
  },
195
195
  };
196
196
  const view = createView(state, computed);
197
- expect(view.firstName).toBe("John");
198
- expect(view.lastName).toBe("Doe");
199
- expect(view.fullName).toBe("John Doe");
200
- state.firstName = "Jane";
201
- expect(view.fullName).toBe("Jane Doe");
197
+ expect(view.firstName).toBe('John');
198
+ expect(view.lastName).toBe('Doe');
199
+ expect(view.fullName).toBe('John Doe');
200
+ state.firstName = 'Jane';
201
+ expect(view.fullName).toBe('Jane Doe');
202
202
  });
203
203
  });
package/dist/error.d.ts CHANGED
@@ -1,5 +1,16 @@
1
- export declare const CatchErrorContext: import("./createContext").Context<(error: unknown) => void>;
2
- export declare function useCatchError(): {
1
+ import { Component, VNode } from "inferno";
2
+ export declare class ErrorBoundary extends Component<{
3
+ children: any;
4
+ error: (error: unknown) => VNode;
5
+ }, {
3
6
  error: unknown;
4
- };
7
+ }> {
8
+ getChildContext(): {
9
+ notifyError: (error: unknown) => void;
10
+ };
11
+ state: {
12
+ error: null;
13
+ };
14
+ render(): any;
15
+ }
5
16
  //# sourceMappingURL=error.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,iBAAiB,4CAAyB,OAAO,KAAK,IAAI,CAAG,CAAC;AAE3E,wBAAgB,aAAa;WAQK,OAAO;EAOxC"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE3C,qBAAa,aAAc,SAAQ,SAAS,CAC1C;IAAE,QAAQ,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,CAAA;CAAE,EACnD;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CACnB;IACC,eAAe;6BAEU,OAAO;;IAKhC,KAAK;;MAAmB;IAExB,MAAM;CAOP"}