ripple 0.2.210 → 0.2.211

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,19 @@
1
1
  # ripple
2
2
 
3
+ ## 0.2.211
4
+
5
+ ### Patch Changes
6
+
7
+ - [#694](https://github.com/Ripple-TS/ripple/pull/694)
8
+ [`fa285f4`](https://github.com/Ripple-TS/ripple/commit/fa285f441ab8d748c3dfea6adb463e3ca6d614b5)
9
+ Thanks [@trueadm](https://github.com/trueadm)! - Add a compiler validation error
10
+ for rendering `children` through text interpolation (for example `{children}` or
11
+ `{props.children}`) and direct users to render children as a component
12
+ (`<@children />`) instead.
13
+ - Updated dependencies
14
+ [[`fa285f4`](https://github.com/Ripple-TS/ripple/commit/fa285f441ab8d748c3dfea6adb463e3ca6d614b5)]:
15
+ - ripple@0.2.211
16
+
3
17
  ## 0.2.210
4
18
 
5
19
  ### 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.2.210",
6
+ "version": "0.2.211",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -93,6 +93,6 @@
93
93
  "vscode-languageserver-types": "^3.17.5"
94
94
  },
95
95
  "peerDependencies": {
96
- "ripple": "0.2.210"
96
+ "ripple": "0.2.211"
97
97
  }
98
98
  }
@@ -2496,7 +2496,15 @@ function RipplePlugin(config) {
2496
2496
  }
2497
2497
 
2498
2498
  if (this.value === '#server') {
2499
- return this.parseServerBlock();
2499
+ // Peek ahead to see if this is a server block (#server { ... }) vs
2500
+ // a server identifier expression (#server.fn(), #server.fn().then())
2501
+ let peek_pos = this.end;
2502
+ while (peek_pos < this.input.length && /\s/.test(this.input[peek_pos])) peek_pos++;
2503
+ if (peek_pos < this.input.length && this.input.charCodeAt(peek_pos) === 123) {
2504
+ // Next non-whitespace character is '{' — parse as server block
2505
+ return this.parseServerBlock();
2506
+ }
2507
+ // Otherwise fall through to parse as expression statement (e.g., #server.fn().then(...))
2500
2508
  }
2501
2509
 
2502
2510
  if (this.value === 'component') {
@@ -140,7 +140,6 @@ declare module 'estree' {
140
140
  ServerIdentifier: ServerIdentifier;
141
141
  Text: TextNode;
142
142
  JSXEmptyExpression: ESTreeJSX.JSXEmptyExpression;
143
- ParenthesizedExpression: ParenthesizedExpression;
144
143
  }
145
144
 
146
145
  // Missing estree type
@@ -190,7 +190,8 @@ export function append(anchor, dom, skip_advance) {
190
190
  }
191
191
 
192
192
  // During hydration, if anchor === dom, we're hydrating a child component
193
- // where the "anchor" IS the content. Don't advance past it.
193
+ // where the "anchor" IS the content. Preserve the cursor on the
194
+ // template's hydrated end node so sibling traversal in the parent is correct.
194
195
  if (anchor === dom) {
195
196
  pop(dom);
196
197
  return;
@@ -0,0 +1,139 @@
1
+ import * as _$_ from 'ripple/internal/client';
2
+
3
+ var root = _$_.template(`<div class="layout"><!></div>`, 0);
4
+ var root_1 = _$_.template(`<div class="single">single</div>`, 0);
5
+ var root_2 = _$_.template(`<h1>title</h1><p>description</p>`, 1);
6
+ var root_3 = _$_.template(`<!>`, 1);
7
+ var root_5 = _$_.template(`<!>`, 1);
8
+ var root_4 = _$_.template(`<!>`, 1);
9
+ var root_7 = _$_.template(`<!><div class="extra">extra</div>`, 1);
10
+ var root_6 = _$_.template(`<!>`, 1);
11
+ var root_9 = _$_.template(`<!>`, 1);
12
+ var root_8 = _$_.template(`<!>`, 1);
13
+
14
+ export function Layout(__anchor, __props, __block) {
15
+ _$_.push_component();
16
+
17
+ var div_1 = root();
18
+
19
+ {
20
+ var node = _$_.child(div_1);
21
+
22
+ _$_.composite(() => __props.children, node, {});
23
+ _$_.pop(div_1);
24
+ }
25
+
26
+ _$_.append(__anchor, div_1);
27
+ _$_.pop_component();
28
+ }
29
+
30
+ export function SingleChild(__anchor, _, __block) {
31
+ _$_.push_component();
32
+
33
+ var div_2 = root_1();
34
+
35
+ _$_.append(__anchor, div_2);
36
+ _$_.pop_component();
37
+ }
38
+
39
+ export function MultiRootChild(__anchor, _, __block) {
40
+ _$_.push_component();
41
+
42
+ var fragment = root_2();
43
+
44
+ _$_.next();
45
+ _$_.append(__anchor, fragment, true);
46
+ _$_.pop_component();
47
+ }
48
+
49
+ export function EmptyLayout(__anchor, _, __block) {
50
+ _$_.push_component();
51
+
52
+ var fragment_1 = root_3();
53
+ var node_1 = _$_.first_child_frag(fragment_1);
54
+
55
+ Layout(node_1, {}, _$_.active_block);
56
+ _$_.append(__anchor, fragment_1);
57
+ _$_.pop_component();
58
+ }
59
+
60
+ export function LayoutWithSingleChild(__anchor, _, __block) {
61
+ _$_.push_component();
62
+
63
+ var fragment_2 = root_4();
64
+ var node_2 = _$_.first_child_frag(fragment_2);
65
+
66
+ Layout(
67
+ node_2,
68
+ {
69
+ children(__anchor, _, __block) {
70
+ _$_.push_component();
71
+
72
+ var fragment_3 = root_5();
73
+ var node_3 = _$_.first_child_frag(fragment_3);
74
+
75
+ SingleChild(node_3, {}, _$_.active_block);
76
+ _$_.append(__anchor, fragment_3);
77
+ _$_.pop_component();
78
+ }
79
+ },
80
+ _$_.active_block
81
+ );
82
+
83
+ _$_.append(__anchor, fragment_2);
84
+ _$_.pop_component();
85
+ }
86
+
87
+ export function LayoutWithMultipleChildren(__anchor, _, __block) {
88
+ _$_.push_component();
89
+
90
+ var fragment_4 = root_6();
91
+ var node_4 = _$_.first_child_frag(fragment_4);
92
+
93
+ Layout(
94
+ node_4,
95
+ {
96
+ children(__anchor, _, __block) {
97
+ _$_.push_component();
98
+
99
+ var fragment_5 = root_7();
100
+ var node_5 = _$_.first_child_frag(fragment_5);
101
+
102
+ SingleChild(node_5, {}, _$_.active_block);
103
+ _$_.append(__anchor, fragment_5);
104
+ _$_.pop_component();
105
+ }
106
+ },
107
+ _$_.active_block
108
+ );
109
+
110
+ _$_.append(__anchor, fragment_4);
111
+ _$_.pop_component();
112
+ }
113
+
114
+ export function LayoutWithMultiRootChild(__anchor, _, __block) {
115
+ _$_.push_component();
116
+
117
+ var fragment_6 = root_8();
118
+ var node_6 = _$_.first_child_frag(fragment_6);
119
+
120
+ Layout(
121
+ node_6,
122
+ {
123
+ children(__anchor, _, __block) {
124
+ _$_.push_component();
125
+
126
+ var fragment_7 = root_9();
127
+ var node_7 = _$_.first_child_frag(fragment_7);
128
+
129
+ MultiRootChild(node_7, {}, _$_.active_block);
130
+ _$_.append(__anchor, fragment_7);
131
+ _$_.pop_component();
132
+ }
133
+ },
134
+ _$_.active_block
135
+ );
136
+
137
+ _$_.append(__anchor, fragment_6);
138
+ _$_.pop_component();
139
+ }
@@ -0,0 +1,176 @@
1
+ import * as _$_ from 'ripple/internal/server';
2
+
3
+ export async function Layout(__output, { children }) {
4
+ return _$_.async(async () => {
5
+ _$_.push_component();
6
+ __output.push('<div');
7
+ __output.push(' class="layout"');
8
+ __output.push('>');
9
+
10
+ {
11
+ {
12
+ const comp = children;
13
+ const args = [__output, {}];
14
+
15
+ if (comp?.async) {
16
+ await comp(...args);
17
+ } else if (comp) {
18
+ comp(...args);
19
+ }
20
+ }
21
+ }
22
+
23
+ __output.push('</div>');
24
+ _$_.pop_component();
25
+ });
26
+ }
27
+
28
+ export function SingleChild(__output) {
29
+ _$_.push_component();
30
+ __output.push('<div');
31
+ __output.push(' class="single"');
32
+ __output.push('>');
33
+
34
+ {
35
+ __output.push('single');
36
+ }
37
+
38
+ __output.push('</div>');
39
+ _$_.pop_component();
40
+ }
41
+
42
+ export function MultiRootChild(__output) {
43
+ _$_.push_component();
44
+ __output.push('<h1');
45
+ __output.push('>');
46
+
47
+ {
48
+ __output.push('title');
49
+ }
50
+
51
+ __output.push('</h1>');
52
+ __output.push('<p');
53
+ __output.push('>');
54
+
55
+ {
56
+ __output.push('description');
57
+ }
58
+
59
+ __output.push('</p>');
60
+ _$_.pop_component();
61
+ }
62
+
63
+ export function EmptyLayout(__output) {
64
+ _$_.push_component();
65
+
66
+ {
67
+ const comp = Layout;
68
+ const args = [__output, {}];
69
+
70
+ comp(...args);
71
+ }
72
+
73
+ _$_.pop_component();
74
+ }
75
+
76
+ export function LayoutWithSingleChild(__output) {
77
+ _$_.push_component();
78
+
79
+ {
80
+ const comp = Layout;
81
+
82
+ const args = [
83
+ __output,
84
+
85
+ {
86
+ children: function children(__output) {
87
+ _$_.push_component();
88
+
89
+ {
90
+ const comp = SingleChild;
91
+ const args = [__output, {}];
92
+
93
+ comp(...args);
94
+ }
95
+
96
+ _$_.pop_component();
97
+ }
98
+ }
99
+ ];
100
+
101
+ comp(...args);
102
+ }
103
+
104
+ _$_.pop_component();
105
+ }
106
+
107
+ export function LayoutWithMultipleChildren(__output) {
108
+ _$_.push_component();
109
+
110
+ {
111
+ const comp = Layout;
112
+
113
+ const args = [
114
+ __output,
115
+
116
+ {
117
+ children: function children(__output) {
118
+ _$_.push_component();
119
+
120
+ {
121
+ const comp = SingleChild;
122
+ const args = [__output, {}];
123
+
124
+ comp(...args);
125
+ }
126
+
127
+ __output.push('<div');
128
+ __output.push(' class="extra"');
129
+ __output.push('>');
130
+
131
+ {
132
+ __output.push('extra');
133
+ }
134
+
135
+ __output.push('</div>');
136
+ _$_.pop_component();
137
+ }
138
+ }
139
+ ];
140
+
141
+ comp(...args);
142
+ }
143
+
144
+ _$_.pop_component();
145
+ }
146
+
147
+ export function LayoutWithMultiRootChild(__output) {
148
+ _$_.push_component();
149
+
150
+ {
151
+ const comp = Layout;
152
+
153
+ const args = [
154
+ __output,
155
+
156
+ {
157
+ children: function children(__output) {
158
+ _$_.push_component();
159
+
160
+ {
161
+ const comp = MultiRootChild;
162
+ const args = [__output, {}];
163
+
164
+ comp(...args);
165
+ }
166
+
167
+ _$_.pop_component();
168
+ }
169
+ }
170
+ ];
171
+
172
+ comp(...args);
173
+ }
174
+
175
+ _$_.pop_component();
176
+ }
@@ -0,0 +1,37 @@
1
+ export component Layout({ children }) {
2
+ <div class="layout">
3
+ <children />
4
+ </div>
5
+ }
6
+
7
+ export component SingleChild() {
8
+ <div class="single">{'single'}</div>
9
+ }
10
+
11
+ export component MultiRootChild() {
12
+ <h1>{'title'}</h1>
13
+ <p>{'description'}</p>
14
+ }
15
+
16
+ export component EmptyLayout() {
17
+ <Layout />
18
+ }
19
+
20
+ export component LayoutWithSingleChild() {
21
+ <Layout>
22
+ <SingleChild />
23
+ </Layout>
24
+ }
25
+
26
+ export component LayoutWithMultipleChildren() {
27
+ <Layout>
28
+ <SingleChild />
29
+ <div class="extra">{'extra'}</div>
30
+ </Layout>
31
+ }
32
+
33
+ export component LayoutWithMultiRootChild() {
34
+ <Layout>
35
+ <MultiRootChild />
36
+ </Layout>
37
+ }
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { hydrateComponent, container } from '../setup-hydration.js';
3
+
4
+ import * as ServerComponents from './compiled/server/composite.js';
5
+ import * as ClientComponents from './compiled/client/composite.js';
6
+
7
+ describe('hydration > composite', () => {
8
+ it('hydrates a layout with no children', async () => {
9
+ await hydrateComponent(ServerComponents.EmptyLayout, ClientComponents.EmptyLayout);
10
+ expect(container.innerHTML).toBeHtml('<div class=\"layout\"></div>');
11
+ });
12
+
13
+ it('hydrates a layout with a single child component', async () => {
14
+ await hydrateComponent(
15
+ ServerComponents.LayoutWithSingleChild,
16
+ ClientComponents.LayoutWithSingleChild,
17
+ );
18
+ expect(container.innerHTML).toBeHtml(
19
+ '<div class=\"layout\"><div class=\"single\">single</div></div>',
20
+ );
21
+ });
22
+
23
+ it('hydrates a layout with multiple children', async () => {
24
+ await hydrateComponent(
25
+ ServerComponents.LayoutWithMultipleChildren,
26
+ ClientComponents.LayoutWithMultipleChildren,
27
+ );
28
+ expect(container.innerHTML).toBeHtml(
29
+ '<div class=\"layout\"><div class=\"single\">single</div><div class=\"extra\">extra</div></div>',
30
+ );
31
+ });
32
+
33
+ it('hydrates a layout with a child that has multiple roots', async () => {
34
+ await hydrateComponent(
35
+ ServerComponents.LayoutWithMultiRootChild,
36
+ ClientComponents.LayoutWithMultiRootChild,
37
+ );
38
+ expect(container.innerHTML).toBeHtml(
39
+ '<div class=\"layout\"><h1>title</h1><p>description</p></div>',
40
+ );
41
+ });
42
+ });