ripple 0.2.47 → 0.2.49

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.
@@ -269,7 +269,7 @@ const visitors = {
269
269
  const parent_node = path?.at(-1);
270
270
 
271
271
  // We're reading a computed property, which might mean it's a reactive property
272
- if (parent_node?.type === 'MemberExpression' && parent_node.computed) {
272
+ if (!ref.node.tracked && parent_node?.type === 'MemberExpression' && parent_node.computed) {
273
273
  binding.transform = {
274
274
  assign: (node, value, computed) => {
275
275
  if (!computed) {
@@ -120,30 +120,36 @@ const visitors = {
120
120
  Identifier(node, context) {
121
121
  const parent = /** @type {Node} */ (context.path.at(-1));
122
122
 
123
- if (is_reference(node, parent) && !context.state.to_ts) {
124
- const binding = context.state.scope.get(node.name);
125
- if (
126
- (context.state.metadata?.tracking === false ||
127
- (parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression')) &&
128
- (is_tracked_name(node.name) ||
129
- node.tracked ||
130
- binding?.kind === 'prop' ||
131
- binding?.kind === 'prop_fallback') &&
132
- binding?.node !== node
133
- ) {
134
- if (context.state.metadata?.tracking === false) {
135
- context.state.metadata.tracking = true;
123
+ if (is_reference(node, parent)) {
124
+ if (context.state.to_ts) {
125
+ if (node.tracked) {
126
+ return b.member(node, b.literal('#v'), true)
127
+ }
128
+ } else {
129
+ const binding = context.state.scope.get(node.name);
130
+ if (
131
+ (context.state.metadata?.tracking === false ||
132
+ (parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression')) &&
133
+ (is_tracked_name(node.name) ||
134
+ node.tracked ||
135
+ binding?.kind === 'prop' ||
136
+ binding?.kind === 'prop_fallback') &&
137
+ binding?.node !== node
138
+ ) {
139
+ if (context.state.metadata?.tracking === false) {
140
+ context.state.metadata.tracking = true;
141
+ }
142
+ if (node.tracked) {
143
+ return b.call('$.get', build_getter(node, context));
144
+ }
136
145
  }
137
- if (node.tracked) {
138
- return b.call('$.get', build_getter(node, context));
146
+
147
+ if (node.name === 'structuredClone' && binding === null) {
148
+ return b.id('$.structured_clone');
139
149
  }
140
- }
141
150
 
142
- if (node.name === 'structuredClone' && binding === null) {
143
- return b.id('$.structured_clone');
151
+ return build_getter(node, context);
144
152
  }
145
-
146
- return build_getter(node, context);
147
153
  }
148
154
  },
149
155
 
@@ -435,6 +435,9 @@ export function is_value_static(node) {
435
435
  }
436
436
 
437
437
  export function is_tracked_computed_property(object, property, context) {
438
+ if (object.tracked) {
439
+ return false;
440
+ }
438
441
  const binding = context.state.scope.get(object.name);
439
442
 
440
443
  if (binding) {
@@ -693,13 +696,13 @@ const common_dom_names = new Set([
693
696
 
694
697
  export function is_element_dom_element(node, context) {
695
698
  if (node.id.type === 'Identifier' && node.id.name[0].toLowerCase() === node.id.name[0]) {
696
- if (common_dom_names.has(node.id.name)) {
697
- return true;
698
- }
699
- const binding = context.state.scope.get(node.id.name);
699
+ if (common_dom_names.has(node.id.name)) {
700
+ return true;
701
+ }
702
+ const binding = context.state.scope.get(node.id.name);
700
703
  if (binding == null) {
701
- return true;
702
- }
704
+ return true;
705
+ }
703
706
  }
704
707
  return false;
705
708
  }
@@ -163,7 +163,7 @@ function push_block(block, parent_block) {
163
163
  export function block(flags, fn, state = null) {
164
164
  /** @type {Block} */
165
165
  var block = {
166
- c: active_component,
166
+ co: active_component,
167
167
  d: null,
168
168
  first: null,
169
169
  f: flags,
@@ -170,7 +170,7 @@ function run_derived(computed) {
170
170
  active_reaction = computed;
171
171
  tracking = true;
172
172
  active_dependency = null;
173
- active_component = active_block.c;
173
+ active_component = computed.co;
174
174
 
175
175
  destroy_computed_children(computed);
176
176
 
@@ -221,7 +221,7 @@ export function run_block(block) {
221
221
  try {
222
222
  active_block = block;
223
223
  active_reaction = block;
224
- active_component = block.c;
224
+ active_component = block.co;
225
225
 
226
226
  destroy_non_branch_children(block);
227
227
  run_teardown(block);
@@ -279,6 +279,7 @@ export function derived(fn, block) {
279
279
  b: block,
280
280
  blocks: null,
281
281
  c: 0,
282
+ co: active_component,
282
283
  d: null,
283
284
  f: TRACKED | DERIVED,
284
285
  fn,
@@ -28,6 +28,7 @@ export type Derived = {
28
28
  b: Block;
29
29
  blocks: null | Block[];
30
30
  c: number;
31
+ co: null | Component;
31
32
  d: null;
32
33
  f: number;
33
34
  fn: Function;
@@ -35,7 +36,7 @@ export type Derived = {
35
36
  };
36
37
 
37
38
  export type Block = {
38
- c: null | Component;
39
+ co: null | Component;
39
40
  d: null | Dependency;
40
41
  first: null | Block;
41
42
  f: number;
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { mount, RippleArray } from 'ripple';
2
+ import { mount, RippleArray, track } from 'ripple';
3
3
  import { parse } from 'ripple/compiler'
4
4
 
5
5
  describe('compiler success tests', () => {
@@ -109,15 +109,15 @@ describe('compiler success tests', () => {
109
109
 
110
110
  component App() {
111
111
  let items = [];
112
- let $items = [];
112
+ let tracked_items = track([]);
113
113
  let items2 = new Array();
114
114
  let items3 = new RippleArray();
115
115
  let i = 0;
116
116
 
117
117
  logs.push(items[0]);
118
118
  logs.push(items[i]);
119
- logs.push($items[0]);
120
- logs.push($items[i]);
119
+ logs.push(@tracked_items[0]);
120
+ logs.push(@tracked_items[i]);
121
121
  logs.push(items2[0]);
122
122
  logs.push(items2[i]);
123
123
  logs.push(items3[0]);
@@ -125,8 +125,8 @@ describe('compiler success tests', () => {
125
125
 
126
126
  items[0] = 123;
127
127
  items[i] = 123;
128
- $items[0] = 123;
129
- $items[i] = 123;
128
+ @tracked_items[0] = 123;
129
+ @tracked_items[i] = 123;
130
130
  items2[0] = 123;
131
131
  items2[i] = 123;
132
132
  items3[0] = 123;
@@ -134,8 +134,8 @@ describe('compiler success tests', () => {
134
134
 
135
135
  logs.push(items[0]);
136
136
  logs.push(items[i]);
137
- logs.push($items[0]);
138
- logs.push($items[i]);
137
+ logs.push(@tracked_items[0]);
138
+ logs.push(@tracked_items[i]);
139
139
  logs.push(items2[0]);
140
140
  logs.push(items2[i]);
141
141
  logs.push(items3[0]);
@@ -143,8 +143,8 @@ describe('compiler success tests', () => {
143
143
 
144
144
  items[0]++;
145
145
  items[i]++;
146
- $items[0]++;
147
- $items[i]++;
146
+ @tracked_items[0]++;
147
+ @tracked_items[i]++;
148
148
  items2[0]++;
149
149
  items2[i]++;
150
150
  items3[0]++;
@@ -152,8 +152,8 @@ describe('compiler success tests', () => {
152
152
 
153
153
  logs.push(items[0]);
154
154
  logs.push(items[i]);
155
- logs.push($items[0]);
156
- logs.push($items[i]);
155
+ logs.push(@tracked_items[0]);
156
+ logs.push(@tracked_items[i]);
157
157
  logs.push(items2[0]);
158
158
  logs.push(items2[i]);
159
159
  logs.push(items3[0]);
@@ -161,8 +161,8 @@ describe('compiler success tests', () => {
161
161
 
162
162
  logs.push(--items[0]);
163
163
  logs.push(--items[i]);
164
- logs.push(--$items[0]);
165
- logs.push(--$items[i]);
164
+ logs.push(--@tracked_items[0]);
165
+ logs.push(--@tracked_items[i]);
166
166
  logs.push(--items2[0]);
167
167
  logs.push(--items2[i]);
168
168
  logs.push(--items3[0]);
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { mount, flushSync, track } from 'ripple';
2
+ import { mount, flushSync, track, RippleArray } from 'ripple';
3
3
 
4
4
  describe('composite components', () => {
5
5
  let container;
@@ -284,4 +284,15 @@ describe('composite components', () => {
284
284
  expect(container.querySelectorAll('div')[0].textContent).toBe('');
285
285
  expect(container.querySelectorAll('div')[1].textContent).toBe('123');
286
286
  });
287
+
288
+ it('handlers generic', () => {
289
+ component ArrayTest() {
290
+ let items = new RippleArray<number>();
291
+ items.push.apply(items, [1, 2, 3, 4, 5]);
292
+
293
+ <pre>{items ? JSON.stringify(items) : 'Loading...'}</pre>
294
+ }
295
+
296
+ render(ArrayTest);
297
+ });
287
298
  });
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { mount, createContext } from 'ripple';
2
+ import { mount, createContext, flushSync, track } from 'ripple';
3
3
 
4
4
  describe('context', () => {
5
5
  let container;
@@ -19,25 +19,48 @@ describe('context', () => {
19
19
  document.body.removeChild(container);
20
20
  });
21
21
 
22
- it('creates a reactive ref with initial value', () => {
23
- const MyContext = createContext(null);
22
+ it('creates a reactive ref with initial value', () => {
23
+ const MyContext = createContext(null);
24
24
 
25
- component Child() {
26
- const value = MyContext.get();
25
+ component Child() {
26
+ const value = MyContext.get();
27
27
 
28
- <div>{value}</div>
29
- }
28
+ <div>{value}</div>
29
+ }
30
30
 
31
- component TestContext() {
32
- const value = MyContext.get();
31
+ component TestContext() {
32
+ const value = MyContext.get();
33
33
 
34
- MyContext.set("Hello from context!");
34
+ MyContext.set("Hello from context!");
35
35
 
36
- <Child />
37
- }
36
+ <Child />
37
+ }
38
38
 
39
39
  render(TestContext);
40
40
 
41
41
  expect(container.querySelector('div').textContent).toBe('Hello from context!');
42
42
  });
43
+
44
+ it('handles context captured inside a computed tracked', () => {
45
+
46
+ const MyContext = createContext(null)
47
+
48
+ const doubleContext = () => {
49
+ const value = MyContext.get()
50
+ return value * 2
51
+ }
52
+
53
+ component App() {
54
+ MyContext.set(4)
55
+
56
+ <h3>{MyContext.get()}</h3>
57
+
58
+ <h4>{'2x:'} {doubleContext()}</h4>
59
+
60
+ MyContext.set(8)
61
+ }
62
+
63
+ render(App);
64
+ flushSync();
65
+ });
43
66
  });
package/types/index.d.ts CHANGED
@@ -16,13 +16,13 @@ export declare class RippleArray<T> extends Array<T> {
16
16
  static from<T, U>(
17
17
  arrayLike: ArrayLike<T>,
18
18
  mapFn: (v: T, k: number) => U,
19
- thisArg?: any
19
+ thisArg?: any,
20
20
  ): RippleArray<U>;
21
21
  static from<T>(iterable: Iterable<T>): RippleArray<T>;
22
22
  static from<T, U>(
23
23
  iterable: Iterable<T>,
24
24
  mapFn: (v: T, k: number) => U,
25
- thisArg?: any
25
+ thisArg?: any,
26
26
  ): RippleArray<U>;
27
27
 
28
28
  static of<T>(...items: T[]): RippleArray<T>;
@@ -40,48 +40,48 @@ export type Context<T> = {
40
40
  export declare function createContext<T>(initialValue: T): Context<T>;
41
41
 
42
42
  export class RippleSet<T> extends Set<T> {
43
- readonly $size: number;
44
- isDisjointFrom(other: RippleSet<T> | Set<T>): boolean;
45
- isSubsetOf(other: RippleSet<T> | Set<T>): boolean;
46
- isSupersetOf(other: RippleSet<T> | Set<T>): boolean;
47
- difference(other: RippleSet<T> | Set<T>): RippleSet<T>;
48
- intersection(other: RippleSet<T> | Set<T>): RippleSet<T>;
49
- symmetricDifference(other: RippleSet<T> | Set<T>): RippleSet<T>;
50
- union(other: RippleSet<T> | Set<T>): RippleSet<T>;
51
- toJSON(): T[];
43
+ readonly $size: number;
44
+ isDisjointFrom(other: RippleSet<T> | Set<T>): boolean;
45
+ isSubsetOf(other: RippleSet<T> | Set<T>): boolean;
46
+ isSupersetOf(other: RippleSet<T> | Set<T>): boolean;
47
+ difference(other: RippleSet<T> | Set<T>): RippleSet<T>;
48
+ intersection(other: RippleSet<T> | Set<T>): RippleSet<T>;
49
+ symmetricDifference(other: RippleSet<T> | Set<T>): RippleSet<T>;
50
+ union(other: RippleSet<T> | Set<T>): RippleSet<T>;
51
+ toJSON(): T[];
52
52
  }
53
53
 
54
54
  export class RippleMap<K, V> extends Map<K, V> {
55
- get $size(): number;
56
- toJSON(): [K, V][];
55
+ get $size(): number;
56
+ toJSON(): [K, V][];
57
57
  }
58
58
 
59
59
  // Compiler-injected runtime symbols (for Ripple component development)
60
60
  declare global {
61
- /**
62
- * Runtime block context injected by the Ripple compiler.
63
- * This is automatically available in component scopes and passed to runtime functions.
64
- */
65
- var __block: any;
66
-
67
- /**
68
- * Ripple runtime namespace - injected by the compiler
69
- * These functions are available in compiled Ripple components for TypeScript analysis
70
- */
71
- var $: {
72
- tracked<T>(value: T, block?: any): T;
73
- tracked_object<T extends Record<string, any>>(obj: T, props: string[], block?: any): T;
74
- computed<T>(fn: () => T, block?: any): T;
75
- scope(): any;
76
- get_tracked(node: any): any;
77
- get_derived(node: any): any;
78
- set(node: any, value: any, block?: any): any;
79
- // Add other runtime functions as needed for TypeScript analysis
80
- };
61
+ /**
62
+ * Runtime block context injected by the Ripple compiler.
63
+ * This is automatically available in component scopes and passed to runtime functions.
64
+ */
65
+ var __block: any;
66
+
67
+ /**
68
+ * Ripple runtime namespace - injected by the compiler
69
+ * These functions are available in compiled Ripple components for TypeScript analysis
70
+ */
71
+ var $: {
72
+ tracked<T>(value: T, block?: any): T;
73
+ tracked_object<T extends Record<string, any>>(obj: T, props: string[], block?: any): T;
74
+ computed<T>(fn: () => T, block?: any): T;
75
+ scope(): any;
76
+ get_tracked(node: any): any;
77
+ get_derived(node: any): any;
78
+ set(node: any, value: any, block?: any): any;
79
+ // Add other runtime functions as needed for TypeScript analysis
80
+ };
81
81
  }
82
82
 
83
83
  export declare function createRefKey(): symbol;
84
84
 
85
- type Tracked<V> = {};
85
+ type Tracked<V> = { '#v': V };
86
86
 
87
- export declare function track<V>(value: V): Tracked<V>;
87
+ export declare function track<V>(value: V | (() => V)): Tracked<V>;