@tsrx/vue 0.0.17 → 0.0.19

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/transform.js +109 -1
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Vue compiler built on @tsrx/core",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.0.17",
6
+ "version": "0.0.19",
7
7
  "type": "module",
8
8
  "publishConfig": {
9
9
  "access": "public"
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "esrap": "^2.1.0",
32
32
  "zimmerframe": "^1.1.2",
33
- "@tsrx/core": "0.0.22"
33
+ "@tsrx/core": "0.0.24"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "vue": ">=3.5",
package/src/transform.js CHANGED
@@ -229,9 +229,14 @@ function render_for_of_as_vapor_template(node, loop_params, body_statements) {
229
229
  }
230
230
 
231
231
  const rendered = statement.argument;
232
+ if (expression_can_skip_rendering(rendered)) {
233
+ return render_for_of_as_flat_map(node, loop_params, rendered);
234
+ }
235
+
232
236
  const key_expression = node.key
233
237
  ? clone_expression_node(node.key)
234
- : find_jsx_key_expression(rendered);
238
+ : (find_jsx_key_expression(rendered) ??
239
+ (node.index ? clone_expression_node(node.index) : null));
235
240
  strip_top_level_jsx_keys(rendered);
236
241
  const children = rendered.type === 'JSXFragment' ? rendered.children : [rendered];
237
242
  const attributes = [
@@ -277,6 +282,109 @@ function render_for_of_as_vapor_template(node, loop_params, body_statements) {
277
282
  });
278
283
  }
279
284
 
285
+ /**
286
+ * @param {any} node
287
+ * @param {any[]} loop_params
288
+ * @param {any} rendered
289
+ * @returns {any}
290
+ */
291
+ function render_for_of_as_flat_map(node, loop_params, rendered) {
292
+ return to_jsx_expression_container({
293
+ type: 'CallExpression',
294
+ callee: {
295
+ type: 'MemberExpression',
296
+ object: clone_expression_node(node.right),
297
+ property: { type: 'Identifier', name: 'flatMap', metadata: { path: [] } },
298
+ computed: false,
299
+ optional: false,
300
+ metadata: { path: [] },
301
+ },
302
+ arguments: [
303
+ {
304
+ type: 'ArrowFunctionExpression',
305
+ params: loop_params,
306
+ body: {
307
+ type: 'BlockStatement',
308
+ body: [
309
+ {
310
+ type: 'ReturnStatement',
311
+ argument: to_array_render_expression(rendered),
312
+ metadata: { path: [] },
313
+ },
314
+ ],
315
+ metadata: { path: [] },
316
+ },
317
+ async: false,
318
+ generator: false,
319
+ expression: false,
320
+ metadata: { path: [] },
321
+ },
322
+ ],
323
+ async: false,
324
+ optional: false,
325
+ metadata: { path: [] },
326
+ });
327
+ }
328
+
329
+ /**
330
+ * `<template v-for>` preserves one rendered slot per source item in the current
331
+ * Vue runtime path. Loop bodies that can return `null` need the shared callback
332
+ * lowering so `continue` truly skips the iteration.
333
+ *
334
+ * @param {any} node
335
+ * @returns {boolean}
336
+ */
337
+ function expression_can_skip_rendering(node) {
338
+ if (!node || typeof node !== 'object') {
339
+ return false;
340
+ }
341
+
342
+ if (node.type === 'Literal' && node.value === null) {
343
+ return true;
344
+ }
345
+
346
+ if (node.type === 'ConditionalExpression') {
347
+ return (
348
+ expression_can_skip_rendering(node.consequent) ||
349
+ expression_can_skip_rendering(node.alternate)
350
+ );
351
+ }
352
+
353
+ if (node.type === 'LogicalExpression' && node.operator === '&&') {
354
+ return true;
355
+ }
356
+
357
+ return false;
358
+ }
359
+
360
+ /**
361
+ * @param {any} node
362
+ * @returns {any}
363
+ */
364
+ function to_array_render_expression(node) {
365
+ if (node?.type === 'Literal' && node.value === null) {
366
+ return builders.array([]);
367
+ }
368
+
369
+ if (node?.type === 'ConditionalExpression') {
370
+ return builders.conditional(
371
+ node.test,
372
+ to_array_render_expression(node.consequent),
373
+ to_array_render_expression(node.alternate),
374
+ );
375
+ }
376
+
377
+ if (node?.type === 'LogicalExpression' && node.operator === '&&') {
378
+ return builders.conditional(
379
+ node.left,
380
+ to_array_render_expression(node.right),
381
+ builders.array([]),
382
+ );
383
+ }
384
+
385
+ return builders.array([node]);
386
+ }
387
+
280
388
  /**
281
389
  * @param {any[]} loop_params
282
390
  * @returns {any}