ripple 0.2.133 → 0.2.135

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.
@@ -3,7 +3,7 @@ import { track, flushSync } from 'ripple';
3
3
  describe('basic client > components & composition', () => {
4
4
  it('renders with component composition and children', () => {
5
5
  component Card(props) {
6
- <div class='card'>
6
+ <div class="card">
7
7
  <props.children />
8
8
  </div>
9
9
  }
@@ -27,16 +27,14 @@ describe('basic client > components & composition', () => {
27
27
 
28
28
  it('renders with nested components and prop passing', () => {
29
29
  component Button(props) {
30
- <button class={props.variant} onClick={props.onClick}>
31
- {props.label}
32
- </button>
30
+ <button class={props.variant} onClick={props.onClick}>{props.label}</button>
33
31
  }
34
32
 
35
33
  component Card(props) {
36
- <div class='card'>
34
+ <div class="card">
37
35
  <h3>{props.title}</h3>
38
36
  <p>{props.content}</p>
39
- <Button variant='primary' label={props.buttonText} onClick={props.onAction} />
37
+ <Button variant="primary" label={props.buttonText} onClick={props.onAction} />
40
38
  </div>
41
39
  }
42
40
 
@@ -44,12 +42,12 @@ describe('basic client > components & composition', () => {
44
42
  let clicked = track(false);
45
43
 
46
44
  <Card
47
- title='Test Card'
48
- content='This is a test card'
49
- buttonText='Click me'
45
+ title="Test Card"
46
+ content="This is a test card"
47
+ buttonText="Click me"
50
48
  onAction={() => @clicked = true}
51
49
  />
52
- <div class='status'>{@clicked ? 'Clicked' : 'Not clicked'}</div>
50
+ <div class="status">{@clicked ? 'Clicked' : 'Not clicked'}</div>
53
51
  }
54
52
 
55
53
  render(Basic);
@@ -74,8 +72,8 @@ describe('basic client > components & composition', () => {
74
72
 
75
73
  it('renders with reactive component props', () => {
76
74
  component ChildComponent(props) {
77
- <div class='child-content'>{props.@text}</div>
78
- <div class='child-count'>{props.@count}</div>
75
+ <div class="child-content">{props.@text}</div>
76
+ <div class="child-count">{props.@count}</div>
79
77
  }
80
78
 
81
79
  component Basic() {
@@ -83,10 +81,14 @@ describe('basic client > components & composition', () => {
83
81
  let number = track(1);
84
82
 
85
83
  <ChildComponent text={message} count={number} />
86
- <button onClick={() => {
87
- @message = @message === 'Hello' ? 'Goodbye' : 'Hello';
88
- @number++;
89
- }}>{'Update Props'}</button>
84
+ <button
85
+ onClick={() => {
86
+ @message = @message === 'Hello' ? 'Goodbye' : 'Hello';
87
+ @number++;
88
+ }}
89
+ >
90
+ {'Update Props'}
91
+ </button>
90
92
  }
91
93
 
92
94
  render(Basic);
@@ -139,7 +141,9 @@ describe('basic client > components & composition', () => {
139
141
  @hasError = true;
140
142
  }
141
143
  }}
142
- >{'Nonexistent'}</button>
144
+ >
145
+ {'Nonexistent'}
146
+ </button>
143
147
  <button
144
148
  onClick={() => {
145
149
  @hasError = false;
@@ -149,7 +153,9 @@ describe('basic client > components & composition', () => {
149
153
  @hasError = true;
150
154
  }
151
155
  }}
152
- >{'Nonexistent chaining'}</button>
156
+ >
157
+ {'Nonexistent chaining'}
158
+ </button>
153
159
  <button
154
160
  onClick={() => {
155
161
  @hasError = false;
@@ -159,7 +165,9 @@ describe('basic client > components & composition', () => {
159
165
  @hasError = true;
160
166
  }
161
167
  }}
162
- >{'Object null'}</button>
168
+ >
169
+ {'Object null'}
170
+ </button>
163
171
  <button
164
172
  onClick={() => {
165
173
  @hasError = false;
@@ -169,7 +177,9 @@ describe('basic client > components & composition', () => {
169
177
  @hasError = true;
170
178
  }
171
179
  }}
172
- >{'Object null chained'}</button>
180
+ >
181
+ {'Object null chained'}
182
+ </button>
173
183
  <button onClick={() => obj.arr[obj.arr.length - 1]()}>{'BinaryExpression prop'}</button>
174
184
 
175
185
  <span>{obj.@count}</span>
@@ -36,19 +36,19 @@ describe('compiler > basics', () => {
36
36
  expect(ast.body[0].declaration.css.source).toEqual(style3);
37
37
  });
38
38
 
39
- it('renders without crashing', () => {
39
+ it('renders without crashing', () => {
40
40
  component App() {
41
41
  let foo;
42
42
  let bar;
43
43
  let baz;
44
44
 
45
45
  foo = {};
46
- foo = {'test': 0};
46
+ foo = { test: 0 };
47
47
  foo['abc'] = 123;
48
48
 
49
- bar = { 'def': 456 };
49
+ bar = { def: 456 };
50
50
 
51
- baz = { 'ghi': 789 };
51
+ baz = { ghi: 789 };
52
52
  baz['jkl'] = 987;
53
53
  }
54
54
 
@@ -56,18 +56,18 @@ describe('compiler > basics', () => {
56
56
  });
57
57
 
58
58
  it('renders without crashing using < character', () => {
59
- component App() {
60
- function bar() {
61
- for (let i = 0; i < 10; i++) {
62
- // do nothing
59
+ component App() {
60
+ function bar() {
61
+ for (let i = 0; i < 10; i++) {
62
+ // do nothing
63
+ }
64
+ const x = 1 < 1;
63
65
  }
64
- const x = 1 < 1;
65
- }
66
66
 
67
- let x = 5 < 10
67
+ let x = 5 < 10;
68
68
 
69
- <div>{x}</div>
70
- }
69
+ <div>{x}</div>
70
+ }
71
71
 
72
72
  render(App);
73
73
  });
@@ -97,28 +97,28 @@ describe('compiler > basics', () => {
97
97
  it('renders without crashing using mapped types', () => {
98
98
  component App() {
99
99
  type RecordKey = 'test';
100
- type RecordValue = { a: string, b: number };
100
+ type RecordValue = { a: string; b: number };
101
101
 
102
102
  const config: Record<RecordKey, RecordValue> = {
103
103
  test: {
104
104
  a: 'test',
105
- b: 1
105
+ b: 1,
106
106
  },
107
107
  };
108
108
 
109
109
  const config2: { [key in RecordKey]: RecordValue } = {
110
110
  test: {
111
111
  a: 'test2',
112
- b: 2
113
- }
114
- }
112
+ b: 2,
113
+ },
114
+ };
115
115
 
116
116
  const config3: { [key: RecordKey]: RecordValue } = {
117
117
  test: {
118
118
  a: 'test3',
119
- b: 3
120
- }
121
- }
119
+ b: 3,
120
+ },
121
+ };
122
122
  }
123
123
 
124
124
  render(App);
@@ -130,11 +130,14 @@ describe('compiler > basics', () => {
130
130
  const { a, b, ...rest } = obj;
131
131
 
132
132
  <div>
133
- {'a '}{a} {'b '} {b} {'rest '} {JSON.stringify(rest)}
134
-
135
- <div>
136
-
137
- </div>
133
+ {'a '}
134
+ {a}
135
+ {'b '}
136
+ {b}
137
+ {'rest '}
138
+ {JSON.stringify(rest)}
139
+
140
+ <div />
138
141
  </div>
139
142
  }
140
143
 
@@ -146,11 +149,14 @@ describe('compiler > basics', () => {
146
149
  const obj = { a: 1, b: 2, c: 3 };
147
150
  const { a, b, ...rest } = obj;
148
151
 
149
- {'a '}{a} {'b '} {b} {'rest '} {JSON.stringify(rest)}
152
+ {'a '}
153
+ {a}
154
+ {'b '}
155
+ {b}
156
+ {'rest '}
157
+ {JSON.stringify(rest)}
150
158
 
151
- <div>
152
-
153
- </div>
159
+ <div />
154
160
  }
155
161
 
156
162
  render(App);
@@ -163,10 +169,10 @@ describe('compiler > basics', () => {
163
169
 
164
170
  function Wrapper() {
165
171
  return {
166
- unwrap: function<T>() {
172
+ unwrap: function() {
167
173
  return null as unknown as T;
168
- }
169
- }
174
+ },
175
+ };
170
176
  }
171
177
 
172
178
  component App() {
@@ -180,11 +186,11 @@ describe('compiler > basics', () => {
180
186
  value: T;
181
187
  }
182
188
 
183
- class Box<T> {
189
+ class Box {
184
190
  value: T;
185
191
 
186
- method<T>(): T {
187
- return this.value;
192
+ method(): T {
193
+ return this.value;
188
194
  }
189
195
  }
190
196
 
@@ -213,7 +219,7 @@ describe('compiler > basics', () => {
213
219
  const result = compile(source, 'test.ripple', { mode: 'client' });
214
220
  });
215
221
 
216
- it("doesn't add duplicate imports when encountering shorthand syntax", () => {
222
+ it('doesn\'t add duplicate imports when encountering shorthand syntax', () => {
217
223
  const source = `
218
224
  import {
219
225
  TrackedArray,
@@ -234,14 +240,14 @@ component App() {
234
240
  `;
235
241
  const result = compile_to_volar_mappings(source, 'test.ripple').code;
236
242
 
237
- expect(count_occurrences(result, "TrackedArray")).toBe(2);
238
- expect(count_occurrences(result, "TrackedObject")).toBe(2);
239
- expect(count_occurrences(result, "TrackedSet")).toBe(2);
240
- expect(count_occurrences(result, "TrackedMap")).toBe(2);
241
- expect(count_occurrences(result, "createRefKey")).toBe(2);
243
+ expect(count_occurrences(result, 'TrackedArray')).toBe(2);
244
+ expect(count_occurrences(result, 'TrackedObject')).toBe(2);
245
+ expect(count_occurrences(result, 'TrackedSet')).toBe(2);
246
+ expect(count_occurrences(result, 'TrackedMap')).toBe(2);
247
+ expect(count_occurrences(result, 'createRefKey')).toBe(2);
242
248
  });
243
249
 
244
- it("doesn't add duplicate imports for renamed imports when encountering shorthand syntax", () => {
250
+ it('doesn\'t add duplicate imports for renamed imports when encountering shorthand syntax', () => {
245
251
  const source = `
246
252
  import {
247
253
  TrackedArray as TA,
@@ -262,16 +268,16 @@ component App() {
262
268
  `;
263
269
  const result = compile_to_volar_mappings(source, 'test.ripple').code;
264
270
 
265
- expect(count_occurrences(result, "TrackedArray")).toBe(1);
266
- expect(count_occurrences(result, "TA")).toBe(2);
267
- expect(count_occurrences(result, "TrackedObject")).toBe(1);
268
- expect(count_occurrences(result, "TO")).toBe(2);
269
- expect(count_occurrences(result, "TrackedSet")).toBe(1);
270
- expect(count_occurrences(result, "TS")).toBe(2);
271
- expect(count_occurrences(result, "TrackedMap")).toBe(1);
272
- expect(count_occurrences(result, "TM")).toBe(2);
273
- expect(count_occurrences(result, "createRefKey")).toBe(1);
274
- expect(count_occurrences(result, "crk")).toBe(2);
271
+ expect(count_occurrences(result, 'TrackedArray')).toBe(1);
272
+ expect(count_occurrences(result, 'TA')).toBe(2);
273
+ expect(count_occurrences(result, 'TrackedObject')).toBe(1);
274
+ expect(count_occurrences(result, 'TO')).toBe(2);
275
+ expect(count_occurrences(result, 'TrackedSet')).toBe(1);
276
+ expect(count_occurrences(result, 'TS')).toBe(2);
277
+ expect(count_occurrences(result, 'TrackedMap')).toBe(1);
278
+ expect(count_occurrences(result, 'TM')).toBe(2);
279
+ expect(count_occurrences(result, 'createRefKey')).toBe(1);
280
+ expect(count_occurrences(result, 'crk')).toBe(2);
275
281
  });
276
282
 
277
283
  it('adds missing imports for shorthand syntax', () => {
@@ -287,11 +293,11 @@ component App() {
287
293
  `;
288
294
  const result = compile_to_volar_mappings(source, 'test.ripple').code;
289
295
 
290
- expect(count_occurrences(result, "TrackedArray")).toBe(2);
291
- expect(count_occurrences(result, "TrackedObject")).toBe(2);
292
- expect(count_occurrences(result, "TrackedSet")).toBe(2);
293
- expect(count_occurrences(result, "TrackedMap")).toBe(2);
294
- expect(count_occurrences(result, "createRefKey")).toBe(2);
296
+ expect(count_occurrences(result, 'TrackedArray')).toBe(2);
297
+ expect(count_occurrences(result, 'TrackedObject')).toBe(2);
298
+ expect(count_occurrences(result, 'TrackedSet')).toBe(2);
299
+ expect(count_occurrences(result, 'TrackedMap')).toBe(2);
300
+ expect(count_occurrences(result, 'createRefKey')).toBe(2);
295
301
  });
296
302
 
297
303
  it('only adds missing imports for shorthand syntax, reusing existing ones', () => {
@@ -309,11 +315,34 @@ component App() {
309
315
  `;
310
316
  const result = compile_to_volar_mappings(source, 'test.ripple').code;
311
317
 
312
- expect(count_occurrences(result, "TrackedArray")).toBe(2);
313
- expect(count_occurrences(result, "TrackedObject")).toBe(2);
314
- expect(count_occurrences(result, "TrackedSet")).toBe(2);
315
- expect(count_occurrences(result, "TrackedMap")).toBe(2);
316
- expect(count_occurrences(result, "createRefKey")).toBe(1);
317
- expect(count_occurrences(result, "crk")).toBe(2);
318
+ expect(count_occurrences(result, 'TrackedArray')).toBe(2);
319
+ expect(count_occurrences(result, 'TrackedObject')).toBe(2);
320
+ expect(count_occurrences(result, 'TrackedSet')).toBe(2);
321
+ expect(count_occurrences(result, 'TrackedMap')).toBe(2);
322
+ expect(count_occurrences(result, 'createRefKey')).toBe(1);
323
+ expect(count_occurrences(result, 'crk')).toBe(2);
324
+ });
325
+
326
+ it('should not error on having js below markup in the same scope', () => {
327
+ const code = `
328
+ component Card(props) {
329
+ <div class="card">
330
+ <props.children />
331
+ </div>
332
+ }
333
+
334
+ export component App() {
335
+ <Card>
336
+ component children() {
337
+ <p>{'Card content here'}</p>
338
+ }
339
+ </Card>
340
+
341
+ const test = 5;
342
+
343
+ <div>{test}</div>
344
+ }
345
+ `;
346
+ expect(() => compile(code, 'test.ripple')).not.toThrow();
318
347
  });
319
348
  });
@@ -0,0 +1,108 @@
1
+ import { compile } from 'ripple/compiler';
2
+ import { track } from 'ripple';
3
+
4
+ describe('Compiler: Tracked Object Direct Access Checks', () => {
5
+
6
+ it('should error on direct access to __v of a tracked object', () => {
7
+ const code = `
8
+ export default component App() {
9
+ let count = track(0);
10
+ console.log(count.__v);
11
+ }
12
+ `;
13
+ expect(() => compile(code, 'test.ripple')).toThrow(/Directly accessing internal property "__v" of a tracked object is not allowed/);
14
+ });
15
+
16
+ it('should error on direct access to "a" (get/set config) of a tracked object', () => {
17
+ const code = `
18
+ export default component App() {
19
+ let myTracked = track(0);
20
+ console.log(myTracked.a);
21
+ }
22
+ `;
23
+ expect(() => compile(code, 'test.ripple')).toThrow(/Directly accessing internal property "a" of a tracked object is not allowed/);
24
+ });
25
+
26
+ it('should error on direct access to "b" (block) of a tracked object', () => {
27
+ const code = `
28
+ export default component App() {
29
+ let myTracked = track(0);
30
+ console.log(myTracked.b);
31
+ }
32
+ `;
33
+ expect(() => compile(code, 'test.ripple')).toThrow(/Directly accessing internal property "b" of a tracked object is not allowed/);
34
+ });
35
+
36
+ it('should error on direct access to "c" (clock) of a tracked object', () => {
37
+ const code = `
38
+ export default component App() {
39
+ let myTracked = track(0);
40
+ console.log(myTracked.c);
41
+ }
42
+ `;
43
+ expect(() => compile(code, 'test.ripple')).toThrow(/Directly accessing internal property "c" of a tracked object is not allowed/);
44
+ });
45
+
46
+ it('should error on direct access to "f" (flags) of a tracked object', () => {
47
+ const code = `
48
+ export default component App() {
49
+ let myTracked = track(0);
50
+ console.log(myTracked.f);
51
+ }
52
+ `;
53
+ expect(() => compile(code, 'test.ripple')).toThrow(/Directly accessing internal property "f" of a tracked object is not allowed/);
54
+ });
55
+
56
+ it('should compile successfully with correct @ syntax access', () => {
57
+ const code = `
58
+ export default component App() {
59
+ let count = track(0);
60
+ console.log(@count);
61
+ }
62
+ `;
63
+ expect(() => compile(code, 'test.ripple')).not.toThrow();
64
+ });
65
+
66
+ it('should compile successfully with correct get() function access', () => {
67
+ const code = `
68
+ import { get, track } from 'ripple';
69
+ export default component App() {
70
+ let count = track(0);
71
+ console.log(get(count));
72
+ }
73
+ `;
74
+ expect(() => compile(code, 'test.ripple')).not.toThrow();
75
+ });
76
+
77
+ it('should not error on accessing __v of a non-tracked object', () => {
78
+ const code = `
79
+ export default component App() {
80
+ let obj = { __v: 123 };
81
+ console.log(obj.__v);
82
+ }
83
+ `;
84
+ expect(() => compile(code, 'test.ripple')).not.toThrow();
85
+ });
86
+
87
+ it('should not error on accessing __v of a non-tracked object (member expression)', () => {
88
+ const code = `
89
+ export default component App() {
90
+ let data = { value: { __v: 456 } };
91
+ console.log(data.value.__v);
92
+ }
93
+ `;
94
+ expect(() => compile(code, 'test.ripple')).not.toThrow();
95
+ });
96
+
97
+ it('should not error on accessing a property named like an internal one on a non-tracked object', () => {
98
+ const code = `
99
+ export default component App() {
100
+ let config = { a: 'some_value', b: 'another_value' };
101
+ console.log(config.a);
102
+ console.log(config.b);
103
+ }
104
+ `;
105
+ expect(() => compile(code, 'test.ripple')).not.toThrow();
106
+ });
107
+
108
+ });
@@ -398,4 +398,123 @@ describe('dynamic DOM elements', () => {
398
398
  expect(stillHasScopedClass).toBe(true);
399
399
  expect(newClasses.includes('even')).toBe(true);
400
400
  });
401
- });
401
+
402
+ it('adds scoping class to dynamic elements', () => {
403
+ component App() {
404
+ let tag = track('div');
405
+
406
+ <@tag class="scoped"><p>{'Scoped dynamic element'}</p></@tag>
407
+
408
+ <style>
409
+ .scoped {
410
+ color: blue;
411
+ }
412
+ </style>
413
+ }
414
+ render(App);
415
+
416
+ const div = container.querySelector('div');
417
+ const p = div.querySelector('p');
418
+
419
+ expect(Array.from(div.classList).some(c => c.startsWith('ripple-'))).toBe(true);
420
+ expect(Array.from(p.classList).some(c => c.startsWith('ripple-'))).toBe(true);
421
+ });
422
+
423
+ it('adds scoping class to dynamic elements when selector targets by tag name', () => {
424
+ component App() {
425
+ let tag = track('div');
426
+
427
+ <@tag class="scoped"><p>{'Scoped dynamic element'}</p></@tag>
428
+
429
+ <style>
430
+ div {
431
+ color: blue;
432
+ }
433
+ </style>
434
+ }
435
+ render(App);
436
+
437
+ const div = container.querySelector('div');
438
+ const p = div.querySelector('p');
439
+
440
+ expect(Array.from(div.classList).some(c => c.startsWith('ripple-'))).toBe(true);
441
+ expect(Array.from(p.classList).some(c => c.startsWith('ripple-'))).toBe(true);
442
+ });
443
+
444
+ it("doesn't add scoping class to components inside dynamic element", () => {
445
+ component Child() {
446
+ <div class="child"><p>{"I am a child component"}</p></div>
447
+
448
+ <style>
449
+ .child {
450
+ color: blue;
451
+ }
452
+ </style>
453
+ }
454
+
455
+ component App() {
456
+ let tag = track('div');
457
+
458
+ <@tag class="scoped">
459
+ <p>{'Scoped dynamic element'}</p>
460
+ <Child />
461
+ </@tag>
462
+
463
+ <style>
464
+ div {
465
+ color: blue;
466
+ }
467
+ </style>
468
+ }
469
+ render(App);
470
+
471
+ const outerDiv = container.querySelector('.scoped');
472
+ const innerDiv = outerDiv.querySelector('.child');
473
+ const innerP = innerDiv.querySelector('p');
474
+
475
+ const outerScope = Array.from(outerDiv.classList).find(c => c.startsWith('ripple-'));
476
+ const innerScopes = Array.from(innerDiv.classList).filter(c => c.startsWith('ripple-'));
477
+ const innerInnerScopes = Array.from(innerP.classList).filter(c => c.startsWith('ripple-'));
478
+
479
+ expect(outerScope).toBeTruthy();
480
+
481
+ expect(innerScopes).toHaveLength(1);
482
+ expect(innerScopes[0]).not.toBe(outerScope);
483
+
484
+ expect(innerInnerScopes).toHaveLength(0);
485
+ });
486
+
487
+ it("doesn't add scoping class to dynamically rendered component", () => {
488
+ component Child() {
489
+ <div class="child"><p>{"I am a child component"}</p></div>
490
+
491
+ <style>
492
+ .child {
493
+ color: green;
494
+ }
495
+ </style>
496
+ }
497
+
498
+ component App() {
499
+ let tag = track(() => Child);
500
+
501
+ <@tag />
502
+
503
+ <style>
504
+ .child {
505
+ color: red;
506
+ }
507
+ </style>
508
+ }
509
+ render(App);
510
+
511
+ const div = container.querySelector('.child');
512
+ const p = div.querySelector('p');
513
+
514
+ const outerScopes = Array.from(div.classList).filter(c => c.startsWith('ripple-'));
515
+ const innerScopes = Array.from(p.classList).filter(c => c.startsWith('ripple-'));
516
+
517
+ expect(outerScopes).toHaveLength(1);
518
+ expect(innerScopes).toHaveLength(0);
519
+ });
520
+ });