ripple 0.2.206 → 0.2.207

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/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.206",
6
+ "version": "0.2.207",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -76,7 +76,7 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@jridgewell/sourcemap-codec": "^1.5.5",
79
- "@sveltejs/acorn-typescript": "^1.0.6",
79
+ "@sveltejs/acorn-typescript": "^1.0.9",
80
80
  "acorn": "^8.15.0",
81
81
  "clsx": "^2.1.1",
82
82
  "devalue": "^5.3.2",
@@ -97,6 +97,6 @@
97
97
  "vscode-languageserver-types": "^3.17.5"
98
98
  },
99
99
  "peerDependencies": {
100
- "ripple": "0.2.206"
100
+ "ripple": "0.2.207"
101
101
  }
102
102
  }
@@ -104,30 +104,28 @@ function visit_function(node, context) {
104
104
  }
105
105
  }
106
106
 
107
- let body = context.visit(node.body, {
108
- ...state,
109
- // we are new context so tracking no longer applies
110
- metadata: { ...state.metadata, tracking: false },
111
- });
112
-
113
- if (metadata?.tracked === true) {
114
- const new_body = [];
115
-
116
- if (!is_inside_component(context, true) && is_component_level_function(context)) {
117
- new_body.push(b.var('__block', b.call('_$_.scope')));
118
- }
119
- if (body.type === 'BlockStatement') {
120
- new_body.push(...body.body);
121
- }
107
+ let body = /** @type {AST.BlockStatement | AST.Expression} */ (
108
+ context.visit(node.body, {
109
+ ...state,
110
+ // we are new context so tracking no longer applies
111
+ metadata: { ...state.metadata, tracking: false },
112
+ })
113
+ );
122
114
 
123
- return {
124
- ...node,
125
- params: node.params.map((param) => context.visit(param, state)),
126
- body: body.type === 'BlockStatement' ? { ...body, body: new_body } : body,
127
- };
115
+ if (
116
+ metadata?.tracked === true &&
117
+ !is_inside_component(context, true) &&
118
+ is_component_level_function(context) &&
119
+ body.type === 'BlockStatement'
120
+ ) {
121
+ body = { ...body, body: [b.var('__block', b.call('_$_.scope')), ...body.body] };
128
122
  }
129
123
 
130
- return context.next(state);
124
+ return {
125
+ ...node,
126
+ params: node.params.map((param) => context.visit(param, state)),
127
+ body,
128
+ };
131
129
  }
132
130
 
133
131
  /**
@@ -2896,12 +2894,20 @@ function transform_children(children, context) {
2896
2894
  : node.type == 'Text'
2897
2895
  ? state.scope.generate('text')
2898
2896
  : state.scope.generate('node'),
2897
+ /** @type {AST.NodeWithLocation} */ (node.type === 'Element' ? node.openingElement : node),
2899
2898
  );
2900
2899
  };
2901
2900
 
2902
2901
  /** @param {AST.Node} node */
2903
2902
  const create_initial = (node) => {
2904
- const id = is_fragment ? b.id(state.scope.generate('fragment')) : get_id(node);
2903
+ const id = is_fragment
2904
+ ? b.id(
2905
+ state.scope.generate('fragment'),
2906
+ /** @type {AST.NodeWithLocation} */ (
2907
+ node.type === 'Element' ? node.openingElement : node
2908
+ ),
2909
+ )
2910
+ : get_id(node);
2905
2911
  initial = id;
2906
2912
  template_id = state.scope.generate('root');
2907
2913
  state.init?.push(b.var(id, b.call(template_id)));
@@ -31,7 +31,11 @@ function remove() {
31
31
  */
32
32
  function remove_when_css_loaded(callback) {
33
33
  /** @type {HTMLLinkElement[]} */
34
- const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
34
+ const links = Array.from(
35
+ /** @type {NodeListOf<HTMLLinkElement>} */ (
36
+ document.querySelectorAll('link[rel="stylesheet"]')
37
+ ),
38
+ );
35
39
  let remaining = links.length;
36
40
 
37
41
  if (remaining === 0) {
@@ -320,10 +320,14 @@ export function get(name, body) {
320
320
 
321
321
  /**
322
322
  * @param {string} name
323
+ * @param {AST.NodeWithLocation} [loc_info]
323
324
  * @returns {AST.Identifier}
324
325
  */
325
- export function id(name) {
326
- return { type: 'Identifier', name, metadata: { path: [] } };
326
+ export function id(name, loc_info) {
327
+ /** @type {AST.Identifier} */
328
+ const node = { type: 'Identifier', name, metadata: { path: [] } };
329
+
330
+ return set_location(node, loc_info);
327
331
  }
328
332
 
329
333
  /**
@@ -231,4 +231,47 @@ describe('basic client > rendering & text', () => {
231
231
  render(App);
232
232
  expect(container).toMatchSnapshot();
233
233
  });
234
+
235
+ it('should handle consecutive text nodes without duplication', () => {
236
+ component App() {
237
+ const Something = conditional('a');
238
+
239
+ <Something />
240
+
241
+ function conditional(item: 'a') {
242
+ let hello = 'Hello';
243
+ const obj = {
244
+ a: component() {
245
+ <div>
246
+ {'a'}
247
+ {' '}
248
+ {hello}
249
+ </div>
250
+ },
251
+ };
252
+
253
+ return obj[item];
254
+ }
255
+ }
256
+
257
+ render(App);
258
+ const div = container.querySelector('div');
259
+ expect(div.textContent).toEqual('a Hello');
260
+ });
261
+
262
+ it('should handle multiple consecutive text expressions', () => {
263
+ component App() {
264
+ let name = 'World';
265
+ <div>
266
+ {'Hello'}
267
+ {' '}
268
+ {name}
269
+ {'!'}
270
+ </div>
271
+ }
272
+
273
+ render(App);
274
+ const div = container.querySelector('div');
275
+ expect(div.textContent).toEqual('Hello World!');
276
+ });
234
277
  });