@tsrx/vue 0.0.18 → 0.0.20

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 +121 -2
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.18",
6
+ "version": "0.0.20",
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.23"
33
+ "@tsrx/core": "0.0.25"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "vue": ">=3.5",
package/src/transform.js CHANGED
@@ -120,9 +120,10 @@ function component_to_vapor_component_declaration(component, transform_context,
120
120
  }
121
121
 
122
122
  const component_id = clone_identifier(component.id);
123
+ const fn_id = fn.type === 'FunctionDeclaration' ? fn.id : null;
123
124
  component_id.metadata = {
124
125
  ...component_id.metadata,
125
- ...(fn.id?.metadata || {}),
126
+ ...(fn_id?.metadata || {}),
126
127
  path: component_id.metadata?.path || [],
127
128
  };
128
129
  /** @type {any} */ (component_id.metadata).hover = create_component_hover_replacement(fn.params);
@@ -229,9 +230,14 @@ function render_for_of_as_vapor_template(node, loop_params, body_statements) {
229
230
  }
230
231
 
231
232
  const rendered = statement.argument;
233
+ if (expression_can_skip_rendering(rendered)) {
234
+ return render_for_of_as_flat_map(node, loop_params, rendered);
235
+ }
236
+
232
237
  const key_expression = node.key
233
238
  ? clone_expression_node(node.key)
234
- : find_jsx_key_expression(rendered);
239
+ : (find_jsx_key_expression(rendered) ??
240
+ (node.index ? clone_expression_node(node.index) : null));
235
241
  strip_top_level_jsx_keys(rendered);
236
242
  const children = rendered.type === 'JSXFragment' ? rendered.children : [rendered];
237
243
  const attributes = [
@@ -277,6 +283,109 @@ function render_for_of_as_vapor_template(node, loop_params, body_statements) {
277
283
  });
278
284
  }
279
285
 
286
+ /**
287
+ * @param {any} node
288
+ * @param {any[]} loop_params
289
+ * @param {any} rendered
290
+ * @returns {any}
291
+ */
292
+ function render_for_of_as_flat_map(node, loop_params, rendered) {
293
+ return to_jsx_expression_container({
294
+ type: 'CallExpression',
295
+ callee: {
296
+ type: 'MemberExpression',
297
+ object: clone_expression_node(node.right),
298
+ property: { type: 'Identifier', name: 'flatMap', metadata: { path: [] } },
299
+ computed: false,
300
+ optional: false,
301
+ metadata: { path: [] },
302
+ },
303
+ arguments: [
304
+ {
305
+ type: 'ArrowFunctionExpression',
306
+ params: loop_params,
307
+ body: {
308
+ type: 'BlockStatement',
309
+ body: [
310
+ {
311
+ type: 'ReturnStatement',
312
+ argument: to_array_render_expression(rendered),
313
+ metadata: { path: [] },
314
+ },
315
+ ],
316
+ metadata: { path: [] },
317
+ },
318
+ async: false,
319
+ generator: false,
320
+ expression: false,
321
+ metadata: { path: [] },
322
+ },
323
+ ],
324
+ async: false,
325
+ optional: false,
326
+ metadata: { path: [] },
327
+ });
328
+ }
329
+
330
+ /**
331
+ * `<template v-for>` preserves one rendered slot per source item in the current
332
+ * Vue runtime path. Loop bodies that can return `null` need the shared callback
333
+ * lowering so `continue` truly skips the iteration.
334
+ *
335
+ * @param {any} node
336
+ * @returns {boolean}
337
+ */
338
+ function expression_can_skip_rendering(node) {
339
+ if (!node || typeof node !== 'object') {
340
+ return false;
341
+ }
342
+
343
+ if (node.type === 'Literal' && node.value === null) {
344
+ return true;
345
+ }
346
+
347
+ if (node.type === 'ConditionalExpression') {
348
+ return (
349
+ expression_can_skip_rendering(node.consequent) ||
350
+ expression_can_skip_rendering(node.alternate)
351
+ );
352
+ }
353
+
354
+ if (node.type === 'LogicalExpression' && node.operator === '&&') {
355
+ return true;
356
+ }
357
+
358
+ return false;
359
+ }
360
+
361
+ /**
362
+ * @param {any} node
363
+ * @returns {any}
364
+ */
365
+ function to_array_render_expression(node) {
366
+ if (node?.type === 'Literal' && node.value === null) {
367
+ return builders.array([]);
368
+ }
369
+
370
+ if (node?.type === 'ConditionalExpression') {
371
+ return builders.conditional(
372
+ node.test,
373
+ to_array_render_expression(node.consequent),
374
+ to_array_render_expression(node.alternate),
375
+ );
376
+ }
377
+
378
+ if (node?.type === 'LogicalExpression' && node.operator === '&&') {
379
+ return builders.conditional(
380
+ node.left,
381
+ to_array_render_expression(node.right),
382
+ builders.array([]),
383
+ );
384
+ }
385
+
386
+ return builders.array([node]);
387
+ }
388
+
280
389
  /**
281
390
  * @param {any[]} loop_params
282
391
  * @returns {any}
@@ -346,6 +455,16 @@ function strip_top_level_jsx_keys(node) {
346
455
  * @returns {any}
347
456
  */
348
457
  function function_declaration_to_expression(fn) {
458
+ if (fn.type === 'ArrowFunctionExpression') {
459
+ return {
460
+ ...fn,
461
+ metadata: {
462
+ ...(fn.metadata || {}),
463
+ path: fn.metadata?.path || [],
464
+ },
465
+ };
466
+ }
467
+
349
468
  return {
350
469
  ...fn,
351
470
  type: 'FunctionExpression',