ripple 0.2.103 → 0.2.105

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.
@@ -287,13 +287,13 @@ describe('compiler success tests', () => {
287
287
  component Child(props) {
288
288
  <div />
289
289
  }
290
-
290
+
291
291
  export default component App() {
292
292
  <Child data-scope="test" aria-label="accessible" class="valid" />
293
293
  }`;
294
294
 
295
295
  const result = compile(source, 'test.ripple', { mode: 'client' });
296
-
296
+
297
297
  // Should contain properly quoted hyphenated properties and unquoted valid identifiers
298
298
  expect(result.js.code).toMatch(/'data-scope': "test"/);
299
299
  expect(result.js.code).toMatch(/'aria-label': "accessible"/);
@@ -323,9 +323,9 @@ describe('compiler success tests', () => {
323
323
  component Child(props) {
324
324
  <div />
325
325
  }
326
-
326
+
327
327
  export default component App() {
328
- <Child
328
+ <Child
329
329
  validProp="valid"
330
330
  class="valid"
331
331
  id="valid"
@@ -336,12 +336,12 @@ describe('compiler success tests', () => {
336
336
  }`;
337
337
 
338
338
  const result = compile(source, 'test.ripple', { mode: 'client' });
339
-
339
+
340
340
  // Valid identifiers should not be quoted
341
341
  expect(result.js.code).toMatch(/validProp: "valid"/);
342
342
  expect(result.js.code).toMatch(/class: "valid"/);
343
343
  expect(result.js.code).toMatch(/id: "valid"/);
344
-
344
+
345
345
  // Invalid identifiers (with hyphens) should be quoted
346
346
  expect(result.js.code).toMatch(/'data-invalid': "invalid"/);
347
347
  expect(result.js.code).toMatch(/'aria-invalid': "invalid"/);
@@ -353,25 +353,113 @@ describe('compiler success tests', () => {
353
353
  component Child(props) {
354
354
  <div />
355
355
  }
356
-
356
+
357
357
  export default component App() {
358
358
  <Child data-scope="test" />
359
359
  }`;
360
360
 
361
361
  const result = compile(source, 'test.ripple', { mode: 'client' });
362
-
362
+
363
363
  // Extract the props object from the generated code and test it's valid JavaScript
364
364
  const match = result.js.code.match(/Child\([^,]+,\s*(\{[^}]+\})/);
365
365
  expect(match).toBeTruthy();
366
-
366
+
367
367
  const propsObject = match[1];
368
368
  expect(() => {
369
369
  // Test that the object literal is syntactically valid
370
370
  new Function(`return ${propsObject}`);
371
371
  }).not.toThrow();
372
-
372
+
373
373
  // Also verify it contains the expected quoted property
374
374
  expect(propsObject).toMatch(/'data-scope': "test"/);
375
375
  });
376
376
  });
377
+
378
+ describe('regex handling', () => {
379
+ it('renders without crashing using regex literals in method calls', () => {
380
+ component App() {
381
+ let text = 'Hello <span>world</span> and <div>content</div>';
382
+
383
+ // Test various regex patterns in method calls that previously failed
384
+ let matchResult = text.match(/<span>/);
385
+ let replaceResult = text.replace(/<div>/g, '[DIV]');
386
+ let searchResult = text.search(/<span>/);
387
+
388
+ // Test regex literals in variable assignments (should work)
389
+ let spanRegex = /<span>/g;
390
+ let divRegex = /<div.*?>/;
391
+
392
+ // Test more complex regex patterns
393
+ let complexMatch = text.match(/<[^>]*>/g);
394
+ let htmlTags = text.replace(/<(\/*)(\w+)[^>]*>/g, '[$1$2]');
395
+
396
+ // Test edge cases with multiple angle brackets
397
+ let multiAngle = '<<test>> <span>content</span>'.match(/<span>/);
398
+
399
+ <div>
400
+ <span>{String(matchResult)}</span>
401
+ <span>{replaceResult}</span>
402
+ <span>{String(searchResult)}</span>
403
+ <span>{String(spanRegex)}</span>
404
+ <span>{String(divRegex)}</span>
405
+ <span>{String(complexMatch)}</span>
406
+ <span>{htmlTags}</span>
407
+ <span>{String(multiAngle)}</span>
408
+ </div>
409
+ }
410
+
411
+ render(App);
412
+
413
+ const matchResult = container.querySelectorAll('span')[0];
414
+ const replaceResult = container.querySelectorAll('span')[1];
415
+ const searchResult = container.querySelectorAll('span')[2];
416
+ const spanRegex = container.querySelectorAll('span')[3];
417
+ const divRegex = container.querySelectorAll('span')[4];
418
+ const complexMatch = container.querySelectorAll('span')[5];
419
+ const htmlTags = container.querySelectorAll('span')[6];
420
+ const multiAngle = container.querySelectorAll('span')[7];
421
+
422
+ expect(matchResult.textContent).toBe('<span>');
423
+ expect(replaceResult.textContent).toBe('Hello <span>world</span> and [DIV]content</div>');
424
+ expect(searchResult.textContent).toBe('6');
425
+ expect(spanRegex.textContent).toBe('/<span>/g');
426
+ expect(divRegex.textContent).toBe('/<div.*?>/');
427
+ expect(complexMatch.textContent).toBe('<span>,</span>,<div>,</div>');
428
+ expect(htmlTags.textContent).toBe('Hello [span]world[/span] and [div]content[/div]');
429
+ expect(multiAngle.textContent).toBe('<span>');
430
+ });
431
+
432
+ it('renders without crashing mixing regex and JSX syntax', () => {
433
+ component App() {
434
+ let htmlString = '<p>Paragraph</p><div>Content</div>';
435
+
436
+ // Mix of regex parsing and legitimate JSX
437
+ let paragraphs = htmlString.match(/<p[^>]*>.*?<\/p>/g);
438
+ let cleaned = htmlString.replace(/<\/?[^>]+>/g, '');
439
+ let splitArray = htmlString.split(/<\/?\w+>/g).filter(s => s.trim());
440
+
441
+ <div class='container'>
442
+ <span class='result'>{String(paragraphs)}</span>
443
+ <span class='cleaned'>{cleaned}</span>
444
+ <p>{'This is real JSX'}</p>
445
+ <div><span>
446
+ {'Split result: '}
447
+ {splitArray.join(', ')}
448
+ </span></div>
449
+ </div>
450
+ }
451
+
452
+ render(App);
453
+
454
+ const result = container.querySelector('.result');
455
+ const cleaned = container.querySelector('.cleaned');
456
+ const jsxParagraph = container.querySelector('p');
457
+ const splitResult = container.querySelector('.container > div > span');
458
+
459
+ expect(result.textContent).toBe('<p>Paragraph</p>');
460
+ expect(cleaned.textContent).toBe('ParagraphContent');
461
+ expect(jsxParagraph.textContent).toBe('This is real JSX');
462
+ expect(splitResult.textContent).toBe('Split result: Paragraph, Content');
463
+ });
464
+ });
377
465
  });
@@ -0,0 +1,46 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mount, flushSync, TrackedSet, track } from 'ripple';
3
+
4
+ describe('TrackedExpression tests', () => {
5
+ let container;
6
+
7
+ function render(component) {
8
+ mount(component, {
9
+ target: container
10
+ });
11
+ }
12
+
13
+ beforeEach(() => {
14
+ container = document.createElement('div');
15
+ document.body.appendChild(container);
16
+ });
17
+
18
+ afterEach(() => {
19
+ document.body.removeChild(container);
20
+ container = null;
21
+ });
22
+
23
+ it('should handle the syntax correctly', () => {
24
+ component App() {
25
+ let count = track(0);
26
+
27
+ function get_count() {
28
+ return count;
29
+ }
30
+
31
+
32
+ <div>{@(count)}</div>
33
+ <div>{@(get_count())}</div>
34
+ <div>{++@(count)}</div>
35
+ <div>{++@(get_count())}</div>
36
+ <div>{@(count)++}</div>
37
+ <div>{@(get_count())++}</div>
38
+ <div>{@(count)}</div>
39
+ <div>{!@(count)}</div>
40
+ <div>{!!@(count)}</div>
41
+ }
42
+
43
+ render(App);
44
+ expect(container).toMatchSnapshot();
45
+ });
46
+ });