ripple 0.3.64 → 0.3.66

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 (63) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +17 -3
  4. package/src/runtime/index-client.js +47 -8
  5. package/src/runtime/index-server.js +0 -2
  6. package/src/runtime/internal/client/index.js +5 -0
  7. package/src/runtime/internal/client/runtime.js +111 -11
  8. package/src/runtime/internal/client/types.d.ts +5 -0
  9. package/src/runtime/internal/server/blocks.js +1 -0
  10. package/src/runtime/internal/server/index.js +175 -20
  11. package/src/utils/errors.js +13 -0
  12. package/tests/client/async-suspend.test.tsrx +2 -2
  13. package/tests/client/basic/basic.get-set.test.tsrx +26 -26
  14. package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +1 -1
  15. package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +1 -1
  16. package/tests/client/compiler/compiler.assignments.test.tsrx +80 -0
  17. package/tests/client/compiler/compiler.tracked-access.test.tsrx +52 -8
  18. package/tests/client/compiler/compiler.typescript.test.tsrx +23 -0
  19. package/tests/client/lazy-array.test.tsrx +34 -0
  20. package/tests/client/lazy-destructuring.test.tsrx +79 -8
  21. package/tests/client/tracked-index-access.test.tsrx +113 -0
  22. package/tests/client/tsx.test.tsrx +66 -21
  23. package/tests/hydration/compiled/client/basic.js +2 -2
  24. package/tests/hydration/compiled/client/events.js +9 -9
  25. package/tests/hydration/compiled/client/for.js +50 -54
  26. package/tests/hydration/compiled/client/head.js +9 -9
  27. package/tests/hydration/compiled/client/hmr.js +1 -1
  28. package/tests/hydration/compiled/client/html.js +2 -2
  29. package/tests/hydration/compiled/client/if-children.js +14 -14
  30. package/tests/hydration/compiled/client/if.js +10 -10
  31. package/tests/hydration/compiled/client/mixed-control-flow.js +7 -7
  32. package/tests/hydration/compiled/client/portal.js +2 -2
  33. package/tests/hydration/compiled/client/reactivity.js +7 -7
  34. package/tests/hydration/compiled/client/return.js +37 -37
  35. package/tests/hydration/compiled/client/switch.js +8 -8
  36. package/tests/hydration/compiled/client/track-async-serialization.js +12 -12
  37. package/tests/hydration/compiled/client/try.js +116 -33
  38. package/tests/hydration/compiled/server/basic.js +2 -2
  39. package/tests/hydration/compiled/server/events.js +8 -8
  40. package/tests/hydration/compiled/server/for.js +21 -21
  41. package/tests/hydration/compiled/server/head.js +10 -10
  42. package/tests/hydration/compiled/server/hmr.js +1 -1
  43. package/tests/hydration/compiled/server/html.js +1 -1
  44. package/tests/hydration/compiled/server/if-children.js +9 -9
  45. package/tests/hydration/compiled/server/if.js +6 -6
  46. package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
  47. package/tests/hydration/compiled/server/portal.js +1 -1
  48. package/tests/hydration/compiled/server/reactivity.js +7 -7
  49. package/tests/hydration/compiled/server/return.js +14 -14
  50. package/tests/hydration/compiled/server/switch.js +4 -4
  51. package/tests/hydration/compiled/server/track-async-serialization.js +12 -12
  52. package/tests/hydration/compiled/server/try.js +116 -4
  53. package/tests/hydration/components/basic.tsrx +3 -1
  54. package/tests/hydration/components/try.tsrx +26 -0
  55. package/tests/hydration/try.test.js +100 -1
  56. package/tests/server/await.test.tsrx +1 -1
  57. package/tests/server/basic.test.tsrx +3 -1
  58. package/tests/server/compiler.test.tsrx +109 -0
  59. package/tests/server/lazy-destructuring.test.tsrx +62 -0
  60. package/tests/server/tracked-index-access.test.tsrx +76 -0
  61. package/tests/setup-hydration.js +31 -0
  62. package/types/index.d.ts +11 -9
  63. package/types/server.d.ts +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # ripple
2
2
 
3
+ ## 0.3.66
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1166](https://github.com/Ripple-TS/ripple/pull/1166)
8
+ [`1dc0331`](https://github.com/Ripple-TS/ripple/commit/1dc0331f7b7296545ee459dc31a92057871cbb0d)
9
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Replace all [0] and [1]
10
+ compiled output with `.value` and direct `lazy` Throw runtime errors for direct
11
+ `[0]` and `[1]` access on tracked and derived values. Fix type removal for
12
+ non-tsx paths Remove the public `get` and `set` exports in favor of `.value`
13
+ access. Ignore lazy writes past the tracked tuple length instead of creating
14
+ numeric properties.
15
+
16
+ - [#1169](https://github.com/Ripple-TS/ripple/pull/1169)
17
+ [`bf1cb96`](https://github.com/Ripple-TS/ripple/commit/bf1cb96f2ea9b325e30f5a051c451f92659d20f9)
18
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Type host `ref={...}`
19
+ attributes, named ref props, and generated ref keys so inline callbacks
20
+ `{ref ...}` receive element-specific JSX types.
21
+
22
+ Exclude `returnType` from the compiler types that use typeAnnotation instead due
23
+ to the way `@sveltejs/acorn-typescript` parses them.
24
+
25
+ - [#1168](https://github.com/Ripple-TS/ripple/pull/1168)
26
+ [`146cbf5`](https://github.com/Ripple-TS/ripple/commit/146cbf58120aad05161d503118a47bdc566ba869)
27
+ Thanks [@leonidaz](https://github.com/leonidaz)! - Add global root pending/catch
28
+ boundary support and allow Ripple config routes to reference named entry
29
+ exports.
30
+
31
+ Refactor vite-plugin to keep code generation in one place, produce cache as
32
+ necessary and generate actual files for inspection.
33
+
34
+ - Updated dependencies
35
+ [[`1dc0331`](https://github.com/Ripple-TS/ripple/commit/1dc0331f7b7296545ee459dc31a92057871cbb0d),
36
+ [`bf1cb96`](https://github.com/Ripple-TS/ripple/commit/bf1cb96f2ea9b325e30f5a051c451f92659d20f9)]:
37
+ - @tsrx/ripple@0.1.14
38
+ - @tsrx/core@0.1.14
39
+
40
+ ## 0.3.65
41
+
42
+ ### Patch Changes
43
+
44
+ - Updated dependencies
45
+ [[`95c2976`](https://github.com/Ripple-TS/ripple/commit/95c2976b9ec2c20c4160ad13b636c1ed03e863ef)]:
46
+ - @tsrx/core@0.1.13
47
+ - @tsrx/ripple@0.1.13
48
+
3
49
  ## 0.3.64
4
50
 
5
51
  ## 0.3.63
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.64",
6
+ "version": "0.3.66",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -74,8 +74,8 @@
74
74
  "clsx": "^2.1.1",
75
75
  "devalue": "^5.8.1",
76
76
  "esm-env": "^1.2.2",
77
- "@tsrx/core": "0.1.12",
78
- "@tsrx/ripple": "0.1.12"
77
+ "@tsrx/core": "0.1.14",
78
+ "@tsrx/ripple": "0.1.14"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@types/estree": "^1.0.8",
@@ -1,4 +1,4 @@
1
- import type { AddEventObject, TSRXElement } from '#public';
1
+ import type { AddEventObject, RefKey, TSRXElement } from '#public';
2
2
  import type { Nullable } from '#helpers';
3
3
 
4
4
  /**
@@ -67,6 +67,17 @@ type EventHandlerValue<Target extends globalThis.EventTarget, EventType extends
67
67
  | EventHandler<Target, EventType>
68
68
  | EventHandlerObject<Target, EventType>;
69
69
 
70
+ type RefValue<Target extends globalThis.Element> =
71
+ | ((node: Target) => void | (() => void))
72
+ | { value: Target | null }
73
+ | Target
74
+ | null
75
+ | undefined;
76
+
77
+ type RefAttribute<Target extends globalThis.Element> = {
78
+ [Key in RefKey]?: RefValue<Target>;
79
+ };
80
+
70
81
  type ElementEventHandler<
71
82
  Target extends globalThis.EventTarget,
72
83
  Type extends keyof GlobalEventHandlersEventMap,
@@ -459,7 +470,10 @@ type SlotHTMLAttributes<Target extends HTMLSlotElement = HTMLSlotElement> =
459
470
  };
460
471
 
461
472
  // Base HTML attributes
462
- interface HTMLAttributes<Target extends globalThis.Element = globalThis.HTMLElement> {
473
+ interface HTMLAttributes<
474
+ Target extends globalThis.Element = globalThis.HTMLElement,
475
+ > extends RefAttribute<Target> {
476
+ ref?: RefValue<Target>;
463
477
  class?: ClassValue | undefined | null;
464
478
  className?: Nullable<string>;
465
479
  id?: Nullable<string>;
@@ -1255,7 +1269,7 @@ declare global {
1255
1269
  template: HTMLAttributes<HTMLTemplateElement>;
1256
1270
 
1257
1271
  // Catch-all for any other elements
1258
- [elemName: string]: HTMLAttributes<never>;
1272
+ [elemName: string]: HTMLAttributes<any>;
1259
1273
  }
1260
1274
 
1261
1275
  interface ElementChildrenAttribute {
@@ -1,4 +1,4 @@
1
- /** @import { Block, CompatOptions } from '#client' */
1
+ /** @import { Block, CompatOptions, RootBoundaryOptions } from '#client' */
2
2
 
3
3
  import { destroy_block, root } from './internal/client/blocks.js';
4
4
  import { handle_root_events } from './internal/client/events.js';
@@ -9,10 +9,10 @@ import {
9
9
  } from './internal/client/operations.js';
10
10
  import { active_block } from './internal/client/runtime.js';
11
11
  import { create_anchor } from './internal/client/utils.js';
12
+ import { try_block } from './internal/client/try.js';
12
13
  import { remove_ssr_css } from './internal/client/css.js';
13
14
  import {
14
15
  clear_track_hash_reference,
15
- hydrate_next,
16
16
  hydrate_node,
17
17
  hydrating,
18
18
  set_hydrate_node,
@@ -37,9 +37,37 @@ function get_default_compat() {
37
37
  .__RIPPLE_COMPAT__;
38
38
  }
39
39
 
40
+ /**
41
+ * @param {Node} anchor
42
+ * @param {(anchor: Node) => void} render_component
43
+ * @param {RootBoundaryOptions | undefined} boundary
44
+ * @returns {void}
45
+ */
46
+ function render_root_boundary(anchor, render_component, boundary) {
47
+ const Pending = boundary?.pending;
48
+ const Catch = boundary?.catch;
49
+
50
+ try_block(
51
+ anchor,
52
+ (component_anchor) => {
53
+ render_component(component_anchor);
54
+ },
55
+ Catch
56
+ ? (catch_anchor, error, reset) => {
57
+ Catch(catch_anchor, { error, reset: reset ?? (() => {}) }, active_block);
58
+ }
59
+ : null,
60
+ (pending_anchor) => {
61
+ if (Pending) {
62
+ Pending(pending_anchor, {}, active_block);
63
+ }
64
+ },
65
+ );
66
+ }
67
+
40
68
  /**
41
69
  * @param {(anchor: Node, props: Record<string, any>, active_block: Block | null) => void} component
42
- * @param {{ props?: Record<string, any>, target: HTMLElement }} options
70
+ * @param {{ props?: Record<string, any>, target: HTMLElement, rootBoundary?: RootBoundaryOptions }} options
43
71
  * @returns {() => void}
44
72
  */
45
73
  export function mount(component, options) {
@@ -61,7 +89,13 @@ export function mount(component, options) {
61
89
  const cleanup_events = handle_root_events(target);
62
90
 
63
91
  const _root = root(() => {
64
- component(anchor, props, active_block);
92
+ render_root_boundary(
93
+ anchor,
94
+ (component_anchor) => {
95
+ component(component_anchor, props, active_block);
96
+ },
97
+ options.rootBoundary,
98
+ );
65
99
  }, compat);
66
100
 
67
101
  return () => {
@@ -72,7 +106,7 @@ export function mount(component, options) {
72
106
 
73
107
  /**
74
108
  * @param {(anchor: Node, props: Record<string, any>, active_block: Block | null) => void} component
75
- * @param {{ props?: Record<string, any>, target: HTMLElement }} options
109
+ * @param {{ props?: Record<string, any>, target: HTMLElement, rootBoundary?: RootBoundaryOptions }} options
76
110
  * @returns {() => void}
77
111
  */
78
112
  export function hydrate(component, options) {
@@ -99,10 +133,15 @@ export function hydrate(component, options) {
99
133
 
100
134
  set_hydrating(true);
101
135
  set_hydrate_node(/** @type {Comment} */ (anchor));
102
- hydrate_next();
103
136
 
104
137
  _root = root(() => {
105
- component(/** @type {Comment} */ (anchor), props, active_block);
138
+ render_root_boundary(
139
+ /** @type {Comment} */ (anchor),
140
+ (component_anchor) => {
141
+ component(component_anchor, props, active_block);
142
+ },
143
+ options.rootBoundary,
144
+ );
106
145
  }, compat);
107
146
  } catch (e) {
108
147
  throw e;
@@ -154,7 +193,7 @@ export { user_effect as effect } from './internal/client/blocks.js';
154
193
 
155
194
  export { Portal } from './internal/client/portal.js';
156
195
 
157
- export { ref_prop as createRefKey, get, public_set as set } from './internal/client/runtime.js';
196
+ export { ref_prop as createRefKey } from './internal/client/runtime.js';
158
197
 
159
198
  export { isRefProp } from '@tsrx/core/runtime/ref';
160
199
 
@@ -2,8 +2,6 @@ import { output_push, noop } from './internal/server/index.js';
2
2
 
3
3
  export { Context } from './internal/server/context.js';
4
4
  export {
5
- get,
6
- set,
7
5
  untrack,
8
6
  track,
9
7
  track_async as trackAsync,
@@ -46,6 +46,11 @@ export {
46
46
  get,
47
47
  get_tracked,
48
48
  get_derived,
49
+ lazy_array_get,
50
+ lazy_array_rest,
51
+ lazy_array_set,
52
+ lazy_array_update,
53
+ lazy_array_update_pre,
49
54
  set,
50
55
  tracked,
51
56
  spread_props,
@@ -47,6 +47,7 @@ import {
47
47
  import { is_ripple_object } from './utils.js';
48
48
 
49
49
  import {
50
+ iterable_array_from,
50
51
  define_property,
51
52
  get_descriptor,
52
53
  get_own_property_symbols,
@@ -54,6 +55,10 @@ import {
54
55
  object_keys,
55
56
  } from '@tsrx/core/runtime/language-helpers';
56
57
  import { get_async_track_result } from '../../../utils/async.js';
58
+ import {
59
+ throw_tracked_index_reference_error,
60
+ throw_tracked_index_value_error,
61
+ } from '../../../utils/errors.js';
57
62
  import { get_track_async_script_id } from '../../../utils/track-async-serialization.js';
58
63
  import * as devalue from 'devalue';
59
64
  import { hydrating, track_hash_reference } from './hydration.js';
@@ -415,15 +420,15 @@ class TrackedValue {
415
420
  }
416
421
  /** @returns {any} */
417
422
  get [0]() {
418
- return get_tracked(this);
423
+ return throw_tracked_index_value_error();
419
424
  }
420
425
  /** @param {any} v */
421
426
  set [0](v) {
422
- set(this, v);
427
+ throw_tracked_index_value_error();
423
428
  }
424
429
  /** @returns {Tracked} */
425
430
  get [1]() {
426
- return /** @type {Tracked} */ (this);
431
+ return throw_tracked_index_reference_error();
427
432
  }
428
433
  /** @returns {any} */
429
434
  get value() {
@@ -475,15 +480,15 @@ class DerivedValue {
475
480
  }
476
481
  /** @returns {any} */
477
482
  get [0]() {
478
- return get_derived(this);
483
+ return throw_tracked_index_value_error();
479
484
  }
480
485
  /** @param {any} v */
481
486
  set [0](v) {
482
- set(this, v);
487
+ throw_tracked_index_value_error();
483
488
  }
484
489
  /** @returns {Derived} */
485
490
  get [1]() {
486
- return /** @type {Derived} */ (this);
491
+ return throw_tracked_index_reference_error();
487
492
  }
488
493
  /** @returns {any} */
489
494
  get value() {
@@ -1190,6 +1195,60 @@ export function get(tracked) {
1190
1195
  : get_tracked(/** @type {Tracked} */ (tracked));
1191
1196
  }
1192
1197
 
1198
+ /**
1199
+ * @param {any} lazy
1200
+ * @param {number} [index]
1201
+ * @returns {any}
1202
+ */
1203
+ export function lazy_array_get(lazy, index = 0) {
1204
+ if (is_array(lazy)) {
1205
+ return lazy[index];
1206
+ }
1207
+ var flags = lazy.f;
1208
+ if (flags === TRACKED) {
1209
+ return index === 0
1210
+ ? get_tracked(/** @type {Tracked} */ (lazy))
1211
+ : index === 1
1212
+ ? lazy
1213
+ : undefined;
1214
+ }
1215
+ if (flags === DERIVED) {
1216
+ return index === 0
1217
+ ? get_derived(/** @type {Derived} */ (lazy))
1218
+ : index === 1
1219
+ ? lazy
1220
+ : undefined;
1221
+ }
1222
+ return iterable_array_from(lazy, index)[0];
1223
+ }
1224
+
1225
+ /**
1226
+ * @param {any} lazy
1227
+ * @param {number} [index]
1228
+ * @returns {any[]}
1229
+ */
1230
+ export function lazy_array_rest(lazy, index = 0) {
1231
+ if (is_array(lazy)) {
1232
+ return lazy.slice(index);
1233
+ }
1234
+ var flags = lazy.f;
1235
+ if (flags === TRACKED) {
1236
+ return index === 0
1237
+ ? [get_tracked(/** @type {Tracked} */ (lazy)), lazy]
1238
+ : index === 1
1239
+ ? [lazy]
1240
+ : [];
1241
+ }
1242
+ if (flags === DERIVED) {
1243
+ return index === 0
1244
+ ? [get_derived(/** @type {Derived} */ (lazy)), lazy]
1245
+ : index === 1
1246
+ ? [lazy]
1247
+ : [];
1248
+ }
1249
+ return iterable_array_from(lazy, index);
1250
+ }
1251
+
1193
1252
  /**
1194
1253
  * @param {Tracked} tracked
1195
1254
  */
@@ -1214,13 +1273,54 @@ export function get_tracked(tracked) {
1214
1273
  }
1215
1274
 
1216
1275
  /**
1217
- * Exposed version of `set` to avoid internal bugs
1218
- * since block is required on the internal `set`
1219
- * @param {Derived | Tracked} tracked
1276
+ * @param {any} lazy
1220
1277
  * @param {any} value
1278
+ * @param {number} [index]
1279
+ * @returns {void}
1221
1280
  */
1222
- export function public_set(tracked, value) {
1223
- set(tracked, value);
1281
+ export function lazy_array_set(lazy, value, index = 0) {
1282
+ if (is_array(lazy)) {
1283
+ lazy[index] = value;
1284
+ return;
1285
+ }
1286
+ var flags = lazy.f;
1287
+ if (flags === TRACKED || flags === DERIVED) {
1288
+ if (index === 0) {
1289
+ set(/** @type {Derived | Tracked} */ (lazy), value);
1290
+ return;
1291
+ }
1292
+ if (index === 1) {
1293
+ throw_tracked_index_reference_error();
1294
+ }
1295
+ return;
1296
+ }
1297
+ lazy[index] = value;
1298
+ }
1299
+
1300
+ /**
1301
+ * @param {any} lazy
1302
+ * @param {number} [index]
1303
+ * @param {number} [d]
1304
+ * @returns {number}
1305
+ */
1306
+ export function lazy_array_update(lazy, index = 0, d = 1) {
1307
+ var value = lazy_array_get(lazy, index);
1308
+ var result = d === 1 ? value++ : value--;
1309
+ lazy_array_set(lazy, value, index);
1310
+ return result;
1311
+ }
1312
+
1313
+ /**
1314
+ * @param {any} lazy
1315
+ * @param {number} [index]
1316
+ * @param {number} [d]
1317
+ * @returns {number}
1318
+ */
1319
+ export function lazy_array_update_pre(lazy, index = 0, d = 1) {
1320
+ var value = lazy_array_get(lazy, index);
1321
+ var new_value = d === 1 ? ++value : --value;
1322
+ lazy_array_set(lazy, new_value, index);
1323
+ return new_value;
1224
1324
  }
1225
1325
 
1226
1326
  /**
@@ -69,6 +69,11 @@ export type CompatOptions = {
69
69
  [key: string]: CompatApi;
70
70
  };
71
71
 
72
+ export type RootBoundaryOptions = {
73
+ pending?: (anchor: Node, props: Record<string, never>, block: Block | null) => void;
74
+ catch?: (anchor: Node, props: { error: unknown; reset: () => void }, block: Block | null) => void;
75
+ };
76
+
72
77
  declare global {
73
78
  interface Element {
74
79
  __attributes?: {
@@ -88,6 +88,7 @@ export function try_block(try_fn, catch_fn = null, pending_fn = null) {
88
88
  try {
89
89
  try_fn();
90
90
  } catch (error) {
91
+ set_active_block(created_block);
91
92
  if (error === ASYNC_DERIVED_READ_THROWN && created_block.f & TRY_PENDING_BLOCK) {
92
93
  // we should only end up here in the streaming mode during the sync phase
93
94
  created_block.o.clear();