ripple 0.3.54 → 0.3.57

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # ripple
2
2
 
3
+ ## 0.3.57
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1126](https://github.com/Ripple-TS/ripple/pull/1126)
8
+ [`2b1f746`](https://github.com/Ripple-TS/ripple/commit/2b1f7469ab31713140a5baf912a19fa8eedb9234)
9
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Keep runtime helper imports
10
+ on namespaced runtime subpaths so production app bundles do not pull in
11
+ compiler-only modules.
12
+
13
+ - [#1123](https://github.com/Ripple-TS/ripple/pull/1123)
14
+ [`e4a04dd`](https://github.com/Ripple-TS/ripple/commit/e4a04ddb4bbc8e21a9c7c2c65b179d764b72e4fb)
15
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Nested lazy destructuring
16
+ support for all tsrx targets. Ripple already fully supported it.
17
+ - Updated dependencies
18
+ [[`2b1f746`](https://github.com/Ripple-TS/ripple/commit/2b1f7469ab31713140a5baf912a19fa8eedb9234),
19
+ [`e4a04dd`](https://github.com/Ripple-TS/ripple/commit/e4a04ddb4bbc8e21a9c7c2c65b179d764b72e4fb)]:
20
+ - @tsrx/core@0.1.7
21
+ - ripple@0.3.57
22
+ - @tsrx/ripple@0.1.7
23
+
24
+ ## 0.3.56
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies
29
+ [[`a59ccb8`](https://github.com/Ripple-TS/ripple/commit/a59ccb83b91257bf34fca2ba1415e77d1f815a7b)]:
30
+ - @tsrx/core@0.1.6
31
+ - ripple@0.3.56
32
+ - @tsrx/ripple@0.1.6
33
+
34
+ ## 0.3.55
35
+
36
+ ### Patch Changes
37
+
38
+ - Updated dependencies
39
+ [[`de27e18`](https://github.com/Ripple-TS/ripple/commit/de27e182d002ea736aee992acca4cbf9873a307d),
40
+ [`59e1e32`](https://github.com/Ripple-TS/ripple/commit/59e1e328607598fe342abbba35f76e5fadb9ca5c),
41
+ [`1256569`](https://github.com/Ripple-TS/ripple/commit/12565695efaa3a4ad429245807721ea671c2ecb5),
42
+ [`1256569`](https://github.com/Ripple-TS/ripple/commit/12565695efaa3a4ad429245807721ea671c2ecb5),
43
+ [`18b4aef`](https://github.com/Ripple-TS/ripple/commit/18b4aefa8127e56a9f1b3058da2d4d2172551579)]:
44
+ - @tsrx/core@0.1.5
45
+ - ripple@0.3.55
46
+ - @tsrx/ripple@0.1.5
47
+
3
48
  ## 0.3.54
4
49
 
5
50
  ### Patch Changes
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.3.54",
6
+ "version": "0.3.57",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -76,8 +76,8 @@
76
76
  "esm-env": "^1.2.2",
77
77
  "@types/estree": "^1.0.8",
78
78
  "@types/estree-jsx": "^1.0.5",
79
- "@tsrx/core": "0.1.4",
80
- "@tsrx/ripple": "0.1.4"
79
+ "@tsrx/core": "0.1.7",
80
+ "@tsrx/ripple": "0.1.7"
81
81
  },
82
82
  "devDependencies": {
83
83
  "@types/node": "^24.3.0",
@@ -87,6 +87,6 @@
87
87
  "vscode-languageserver-types": "^3.17.5"
88
88
  },
89
89
  "peerDependencies": {
90
- "ripple": "0.3.54"
90
+ "ripple": "0.3.57"
91
91
  }
92
92
  }
@@ -3,11 +3,11 @@
3
3
  * @typedef {EventTarget & Record<string, any>} DelegatedEventTarget
4
4
  */
5
5
  import {
6
- eventNameFromCapture as event_name_from_capture,
7
- isCaptureEvent as is_capture_event,
8
- isNonDelegated as is_non_delegated,
9
- isPassiveEvent as is_passive_event,
10
- } from '@tsrx/core';
6
+ event_name_from_capture,
7
+ is_capture_event,
8
+ is_non_delegated,
9
+ is_passive_event,
10
+ } from '@tsrx/core/runtime/events';
11
11
  import {
12
12
  active_block,
13
13
  active_reaction,
@@ -10,13 +10,10 @@ import {
10
10
  get_prototype_of,
11
11
  } from '@tsrx/core/runtime/language-helpers';
12
12
  import { event } from './events.js';
13
- import {
14
- getAttributeEventName as get_attribute_event_name,
15
- isEventAttribute as is_event_attribute,
16
- } from '@tsrx/core';
13
+ import { get_attribute_event_name, is_event_attribute } from '@tsrx/core/runtime/events';
17
14
  import { get } from './runtime.js';
18
15
  import { clsx } from 'clsx';
19
- import { normalizeCssPropertyName as normalize_css_property_name } from '@tsrx/core';
16
+ import { normalize_css_property_name } from '@tsrx/core/runtime/html';
20
17
 
21
18
  /**
22
19
  * @param {Text} text
@@ -29,10 +29,13 @@ import {
29
29
  import { DEV } from 'esm-env';
30
30
  import { is_ripple_object } from '../client/utils.js';
31
31
  import { array_slice } from '@tsrx/core/runtime/language-helpers';
32
- import { escape, escapeScript as escape_script } from '@tsrx/core';
33
- import { isBooleanAttribute as is_boolean_attribute } from '@tsrx/core';
32
+ import {
33
+ escape,
34
+ escape_script,
35
+ is_boolean_attribute,
36
+ normalize_css_property_name,
37
+ } from '@tsrx/core/runtime/html';
34
38
  import { clsx } from 'clsx';
35
- import { normalizeCssPropertyName as normalize_css_property_name } from '@tsrx/core';
36
39
  import { create_ref_prop } from '@tsrx/core/runtime/ref';
37
40
  import { BLOCK_CLOSE, BLOCK_OPEN } from '../../../constants.js';
38
41
  import { is_tsrx_element, normalize_children, tsrx_element } from '../../element.js';
@@ -53,7 +56,7 @@ import { COMPONENT_BLOCK, TRY_BLOCK } from './constants.js';
53
56
 
54
57
  export { escape };
55
58
  export { register_component_css as register_css } from './css-registry.js';
56
- export { simpleHash as simple_hash, strongHash as strong_hash } from '@tsrx/core';
59
+ export { simple_hash, strong_hash } from '@tsrx/core/runtime/hash';
57
60
  export { context } from './context.js';
58
61
  export { try_block, component_block, regular_block } from './blocks.js';
59
62
  export { array_slice };
@@ -462,12 +462,10 @@ describe('basic client > attribute rendering', () => {
462
462
 
463
463
  it('render spread attributes', () => {
464
464
  component Basic() {
465
- let &[attrs] = track<TestAttributes>(
466
- {
467
- class: 'initial',
468
- id: 'test-1',
469
- },
470
- );
465
+ let &[attrs] = track<TestAttributes>({
466
+ class: 'initial',
467
+ id: 'test-1',
468
+ });
471
469
 
472
470
  <button
473
471
  onClick={() => {
@@ -4,12 +4,10 @@ import { TRACKED_ARRAY } from '../../../src/runtime/internal/client/constants.js
4
4
  describe('basic client > collections', () => {
5
5
  it('renders with simple reactive objects', () => {
6
6
  component Basic() {
7
- let &[user] = track(
8
- {
9
- name: 'John',
10
- age: 25,
11
- },
12
- );
7
+ let &[user] = track({
8
+ name: 'John',
9
+ age: 25,
10
+ });
13
11
 
14
12
  <div class="name">{user.name}</div>
15
13
  <div class="age">{user.age}</div>
@@ -40,12 +38,10 @@ describe('basic client > collections', () => {
40
38
 
41
39
  it('renders with nested reactive objects', () => {
42
40
  component Basic() {
43
- let &[user] = track(
44
- {
45
- name: track('John'),
46
- age: track(25),
47
- },
48
- );
41
+ let &[user] = track({
42
+ name: track('John'),
43
+ age: track(25),
44
+ });
49
45
 
50
46
  <div class="name">{user.name.value}</div>
51
47
  <div class="age">{user.age.value}</div>
@@ -493,12 +493,10 @@ describe('basic server > attribute rendering', () => {
493
493
 
494
494
  it('render spread attributes', async () => {
495
495
  component Basic() {
496
- let &[attrs] = track<TestAttributes>(
497
- {
498
- class: 'initial',
499
- id: 'test-1',
500
- },
501
- );
496
+ let &[attrs] = track<TestAttributes>({
497
+ class: 'initial',
498
+ id: 'test-1',
499
+ });
502
500
 
503
501
  <div {...attrs}>{'Spread Attributes'}</div>
504
502
  }
@@ -140,7 +140,11 @@ describe('lazy destructuring', () => {
140
140
  it(
141
141
  'preserves lazy getter/setter behavior for RestElement nested destructuring in non-lazy component params',
142
142
  async () => {
143
- component Inner({ values: [head, ...&{ 0: first_rest, length: rest_length }] }) {
143
+ component Inner({
144
+ values: [head, ...&{ 0: first_rest, length: rest_length }],
145
+ }: {
146
+ values: number[];
147
+ }) {
144
148
  const before = `${first_rest}-${rest_length}`;
145
149
  rest_length = 0;
146
150
  <pre>{`${head}-${before}-${first_rest}-${rest_length}`}</pre>
@@ -159,7 +163,11 @@ describe('lazy destructuring', () => {
159
163
  'preserves lazy getter/setter behavior for RestElement nested destructuring in non-lazy function params',
160
164
  async () => {
161
165
  component Test() {
162
- function getInfo({ values: [head, ...&{ 0: first_rest, length: rest_length }] }) {
166
+ function getInfo({
167
+ values: [head, ...&{ 0: first_rest, length: rest_length }],
168
+ }: {
169
+ values: number[];
170
+ }) {
163
171
  const before = `${first_rest}-${rest_length}`;
164
172
  rest_length = 0;
165
173
  return `${head}-${before}-${first_rest}-${rest_length}`;
@@ -228,4 +236,304 @@ describe('lazy destructuring', () => {
228
236
  const { body } = await render(Test);
229
237
  expect(body).toBeHtml('<pre>10-20</pre>');
230
238
  });
239
+
240
+ describe('nested lazy destructuring', () => {
241
+ it('preserves nested lazy object access inside lazy object as component params', async () => {
242
+ let inner_value = 7;
243
+
244
+ component Inner(&{ outer: &{ inner } }: { outer: { inner: number } }) {
245
+ const before = inner;
246
+ inner_value = 8;
247
+ <pre>{`${before}-${inner}`}</pre>
248
+ }
249
+
250
+ component Test() {
251
+ const outer = {
252
+ get inner() {
253
+ return inner_value;
254
+ },
255
+ };
256
+ <Inner {outer} />
257
+ }
258
+
259
+ const { body } = await render(Test);
260
+ expect(body).toBeHtml('<pre>7-8</pre>');
261
+ });
262
+
263
+ it('preserves nested lazy array access inside regular object as component params', async () => {
264
+ let first_value = 3;
265
+ let second_value = 4;
266
+
267
+ component Inner({ pair: &[first, second] }: { pair: [number, number] }) {
268
+ const before = `${first}-${second}`;
269
+ first_value = 5;
270
+ second_value = 6;
271
+ <pre>{`${before}-${first}-${second}`}</pre>
272
+ }
273
+
274
+ component Test() {
275
+ const pair = [0, 0] as [number, number];
276
+ Object.defineProperty(pair, 0, { get: () => first_value });
277
+ Object.defineProperty(pair, 1, { get: () => second_value });
278
+ <Inner {pair} />
279
+ }
280
+
281
+ const { body } = await render(Test);
282
+ expect(body).toBeHtml('<pre>3-4-5-6</pre>');
283
+ });
284
+
285
+ it('preserves nested lazy object access inside lazy array as function params', async () => {
286
+ component Test() {
287
+ let name_value = 'Alice';
288
+ function getName(&[&{ name }]: [{ name: string }]) {
289
+ const before = name;
290
+ name_value = 'Bob';
291
+ return `${before}-${name}`;
292
+ }
293
+ const user = {
294
+ get name() {
295
+ return name_value;
296
+ },
297
+ };
298
+ <pre>{getName([user])}</pre>
299
+ }
300
+
301
+ const { body } = await render(Test);
302
+ expect(body).toBeHtml('<pre>Alice-Bob</pre>');
303
+ });
304
+
305
+ it('preserves nested lazy array access inside lazy array as function params', async () => {
306
+ component Test() {
307
+ let first_value = 5;
308
+ let second_value = 6;
309
+ function getValues(&[&[a, b]]: [[number, number]]) {
310
+ const before = `${a}-${b}`;
311
+ first_value = 7;
312
+ second_value = 8;
313
+ return `${before}-${a}-${b}`;
314
+ }
315
+ const pair = [0, 0] as [number, number];
316
+ Object.defineProperty(pair, 0, { get: () => first_value });
317
+ Object.defineProperty(pair, 1, { get: () => second_value });
318
+ <pre>{getValues([pair])}</pre>
319
+ }
320
+
321
+ const { body } = await render(Test);
322
+ expect(body).toBeHtml('<pre>5-6-7-8</pre>');
323
+ });
324
+
325
+ it('preserves three-level lazy object access as component params', async () => {
326
+ let c_value = 42;
327
+
328
+ component Inner(&{ a: &{ b: &{ c } } }: { a: { b: { c: number } } }) {
329
+ const before = c;
330
+ c_value = 43;
331
+ <pre>{`${before}-${c}`}</pre>
332
+ }
333
+
334
+ component Test() {
335
+ const a = {
336
+ b: {
337
+ get c() {
338
+ return c_value;
339
+ },
340
+ },
341
+ };
342
+ <Inner {a} />
343
+ }
344
+
345
+ const { body } = await render(Test);
346
+ expect(body).toBeHtml('<pre>42-43</pre>');
347
+ });
348
+
349
+ it('preserves nested lazy object access inside lazy object as function params', async () => {
350
+ component Test() {
351
+ let inner_value = 11;
352
+ function getValue(&{ outer: &{ inner } }: { outer: { inner: number } }) {
353
+ const before = inner;
354
+ inner_value = 12;
355
+ return `${before}-${inner}`;
356
+ }
357
+ const outer = {
358
+ get inner() {
359
+ return inner_value;
360
+ },
361
+ };
362
+ <pre>{getValue({ outer })}</pre>
363
+ }
364
+
365
+ const { body } = await render(Test);
366
+ expect(body).toBeHtml('<pre>11-12</pre>');
367
+ });
368
+
369
+ it(
370
+ 'supports nested lazy array inside lazy object as function params with writeback',
371
+ async () => {
372
+ component Test() {
373
+ const obj = { pair: [1, 2] as [number, number] };
374
+ function bump(&{ pair: &[first, second] }: { pair: [number, number] }) {
375
+ first = first + 10;
376
+ second = second + 20;
377
+ }
378
+ bump(obj);
379
+ <pre>{`${obj.pair[0]}-${obj.pair[1]}`}</pre>
380
+ }
381
+
382
+ const { body } = await render(Test);
383
+ expect(body).toBeHtml('<pre>11-22</pre>');
384
+ },
385
+ );
386
+
387
+ it('preserves three-level lazy object access as function params', async () => {
388
+ component Test() {
389
+ let c_value = 99;
390
+ function getValue(&{ a: &{ b: &{ c } } }: { a: { b: { c: number } } }) {
391
+ const before = c;
392
+ c_value = 100;
393
+ return `${before}-${c}`;
394
+ }
395
+ const a = {
396
+ b: {
397
+ get c() {
398
+ return c_value;
399
+ },
400
+ },
401
+ };
402
+ <pre>{getValue({ a })}</pre>
403
+ }
404
+
405
+ const { body } = await render(Test);
406
+ expect(body).toBeHtml('<pre>99-100</pre>');
407
+ });
408
+
409
+ it('preserves nested lazy object access inside lazy object in const declaration', async () => {
410
+ component Test() {
411
+ let inner_value = 5;
412
+ const data = {
413
+ outer: {
414
+ get inner() {
415
+ return inner_value;
416
+ },
417
+ },
418
+ };
419
+ const &{ outer: &{ inner } } = data;
420
+ const before = inner;
421
+ inner_value = 6;
422
+ <pre>{`${before}-${inner}`}</pre>
423
+ }
424
+
425
+ const { body } = await render(Test);
426
+ expect(body).toBeHtml('<pre>5-6</pre>');
427
+ });
428
+
429
+ it('supports nested lazy object inside lazy object in let with writeback', async () => {
430
+ component Test() {
431
+ const data = { outer: { inner: 5 } };
432
+ let &{ outer: &{ inner } } = data;
433
+ inner = 50;
434
+ <pre>{data.outer.inner}</pre>
435
+ }
436
+
437
+ const { body } = await render(Test);
438
+ expect(body).toBeHtml('<pre>50</pre>');
439
+ });
440
+
441
+ it('supports nested lazy array inside lazy object in let with writeback', async () => {
442
+ component Test() {
443
+ const data = { pair: [1, 2] as [number, number] };
444
+ let &{ pair: &[first, second] } = data;
445
+ first = 100;
446
+ second = 200;
447
+ <pre>{`${data.pair[0]}-${data.pair[1]}`}</pre>
448
+ }
449
+
450
+ const { body } = await render(Test);
451
+ expect(body).toBeHtml('<pre>100-200</pre>');
452
+ });
453
+
454
+ it('supports three-level lazy object nesting in let with writeback', async () => {
455
+ component Test() {
456
+ const data = { a: { b: { c: 1 } } };
457
+ let &{ a: &{ b: &{ c } } } = data;
458
+ c = 999;
459
+ <pre>{data.a.b.c}</pre>
460
+ }
461
+
462
+ const { body } = await render(Test);
463
+ expect(body).toBeHtml('<pre>999</pre>');
464
+ });
465
+
466
+ it('supports compound assignment on deeply nested lazy bindings', async () => {
467
+ component Test() {
468
+ const data = { a: { b: { c: 5 } } };
469
+ let &{ a: &{ b: &{ c } } } = data;
470
+ c += 10;
471
+ c *= 2;
472
+ <pre>{data.a.b.c}</pre>
473
+ }
474
+
475
+ const { body } = await render(Test);
476
+ expect(body).toBeHtml('<pre>30</pre>');
477
+ });
478
+
479
+ it('preserves default values inside nested lazy destructuring', async () => {
480
+ component Test() {
481
+ let inner_value: number | undefined;
482
+ const data: { outer: { inner?: number } } = {
483
+ outer: {
484
+ get inner() {
485
+ return inner_value;
486
+ },
487
+ },
488
+ };
489
+ const &{ outer: &{ inner = 42 } } = data;
490
+ const before = inner;
491
+ inner_value = 43;
492
+ <pre>{`${before}-${inner}`}</pre>
493
+ }
494
+
495
+ const { body } = await render(Test);
496
+ expect(body).toBeHtml('<pre>42-43</pre>');
497
+ });
498
+
499
+ it('preserves multiple sibling nested lazy destructures', async () => {
500
+ component Test() {
501
+ let x_value = 1;
502
+ let y_value = 2;
503
+ const data = {
504
+ a: {
505
+ get x() {
506
+ return x_value;
507
+ },
508
+ },
509
+ b: {
510
+ get y() {
511
+ return y_value;
512
+ },
513
+ },
514
+ };
515
+ const &{ a: &{ x }, b: &{ y } } = data;
516
+ const before = `${x}-${y}`;
517
+ x_value = 3;
518
+ y_value = 4;
519
+ <pre>{`${before}-${x}-${y}`}</pre>
520
+ }
521
+
522
+ const { body } = await render(Test);
523
+ expect(body).toBeHtml('<pre>1-2-3-4</pre>');
524
+ });
525
+
526
+ it('supports multiple sibling nested lazy destructures with writeback', async () => {
527
+ component Test() {
528
+ const data = { a: { x: 1 }, b: { y: 2 } };
529
+ let &{ a: &{ x }, b: &{ y } } = data;
530
+ x = 11;
531
+ y = 22;
532
+ <pre>{`${data.a.x}-${data.b.y}`}</pre>
533
+ }
534
+
535
+ const { body } = await render(Test);
536
+ expect(body).toBeHtml('<pre>11-22</pre>');
537
+ });
538
+ });
231
539
  });
@@ -0,0 +1,38 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ const runtime_dir = new URL('../../src/runtime/', import.meta.url);
6
+
7
+ /** @param {string} dir */
8
+ async function get_js_files(dir) {
9
+ const entries = await readdir(dir, { withFileTypes: true });
10
+ const files = [];
11
+
12
+ for (const entry of entries) {
13
+ const path = join(dir, entry.name);
14
+ if (entry.isDirectory()) {
15
+ files.push(...(await get_js_files(path)));
16
+ } else if (entry.isFile() && entry.name.endsWith('.js')) {
17
+ files.push(path);
18
+ }
19
+ }
20
+
21
+ return files;
22
+ }
23
+
24
+ describe('runtime imports', () => {
25
+ it('does not import the @tsrx/core compiler barrel', async () => {
26
+ const files = await get_js_files(runtime_dir.pathname);
27
+ const barrel_imports = [];
28
+
29
+ for (const file of files) {
30
+ const source = await readFile(file, 'utf8');
31
+ if (/from\s+['"]@tsrx\/core['"]/.test(source)) {
32
+ barrel_imports.push(file);
33
+ }
34
+ }
35
+
36
+ expect(barrel_imports).toEqual([]);
37
+ });
38
+ });