roqa 0.0.3 → 0.0.4

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
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.0.4] - 2026-01-10
9
+
10
+ ### Fixed
11
+
12
+ - Fixed `set()` calls not notifying subscribers when using cleanup-captured `bind()` calls inside `<For>` and `<Show>` blocks
13
+ - The `findBindCallbacks` function in the inliner now correctly detects `bind()` calls in variable declarations (`const _cleanup_N = bind(...)`) in addition to expression statements
14
+ - This ensures the effect loop is generated for cells with non-inlined bind callbacks
15
+
8
16
  ## [0.0.3] - 2026-01-10
9
17
 
10
18
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roqa",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Roqa is a reactive UI framework",
5
5
  "keywords": [
6
6
  "UI",
@@ -463,61 +463,79 @@ function findBindCallbacks(ast, code) {
463
463
  // Track ref numbers per cell
464
464
  const refCounters = new Map();
465
465
 
466
- traverse(ast, {
467
- ExpressionStatement(path) {
468
- const expr = path.node.expression;
469
- if (!isBindCall(expr)) return;
466
+ /**
467
+ * Process a bind() call expression and add to bindCallbacks
468
+ * @param {object} bindExpr - The bind() CallExpression node
469
+ * @param {number} stmtStart - Start position of containing statement
470
+ * @param {number} stmtEnd - End position of containing statement
471
+ */
472
+ function processBindCall(bindExpr, stmtStart, stmtEnd) {
473
+ const cellArg = bindExpr.arguments[0];
474
+ const callbackArg = bindExpr.arguments[1];
475
+ if (!cellArg || !callbackArg) return;
476
+
477
+ // Get callback info
478
+ if (
479
+ callbackArg.type !== "ArrowFunctionExpression" &&
480
+ callbackArg.type !== "FunctionExpression"
481
+ ) {
482
+ return;
483
+ }
470
484
 
471
- const cellArg = expr.arguments[0];
472
- const callbackArg = expr.arguments[1];
473
- if (!cellArg || !callbackArg) return;
485
+ const cellCode = code.slice(cellArg.start, cellArg.end);
486
+ const paramName = callbackArg.params[0]?.name || "v";
474
487
 
475
- // Get callback info
476
- if (
477
- callbackArg.type !== "ArrowFunctionExpression" &&
478
- callbackArg.type !== "FunctionExpression"
479
- ) {
480
- return;
481
- }
488
+ // Get the callback body
489
+ const body = callbackArg.body;
490
+ let bodyCode;
491
+ if (body.type === "BlockStatement") {
492
+ // Extract statements from block, removing braces
493
+ bodyCode = code.slice(body.start + 1, body.end - 1).trim();
494
+ } else {
495
+ // Expression body
496
+ bodyCode = code.slice(body.start, body.end);
497
+ }
482
498
 
483
- const cellCode = code.slice(cellArg.start, cellArg.end);
484
- const paramName = callbackArg.params[0]?.name || "v";
499
+ // Find element variables used in the callback (e.g., p_1_text, tr_1)
500
+ // Also detect closure variables that would prevent inlining
501
+ const { elementVars, closureVars } = findElementVariables(body, code, paramName, cellCode);
502
+ const hasClosureVars = closureVars.size > 0;
485
503
 
486
- // Get the callback body
487
- const body = callbackArg.body;
488
- let bodyCode;
489
- if (body.type === "BlockStatement") {
490
- // Extract statements from block, removing braces
491
- bodyCode = code.slice(body.start + 1, body.end - 1).trim();
492
- } else {
493
- // Expression body
494
- bodyCode = code.slice(body.start, body.end);
495
- }
504
+ // Get or create ref number for this cell
505
+ const currentRef = refCounters.get(cellCode) || 0;
506
+ const refNum = currentRef + 1;
507
+ refCounters.set(cellCode, refNum);
496
508
 
497
- // Find element variables used in the callback (e.g., p_1_text, tr_1)
498
- // Also detect closure variables that would prevent inlining
499
- const { elementVars, closureVars } = findElementVariables(body, code, paramName, cellCode);
500
- const hasClosureVars = closureVars.size > 0;
509
+ // Store bind callback info
510
+ if (!bindCallbacks.has(cellCode)) {
511
+ bindCallbacks.set(cellCode, []);
512
+ }
501
513
 
502
- // Get or create ref number for this cell
503
- const currentRef = refCounters.get(cellCode) || 0;
504
- const refNum = currentRef + 1;
505
- refCounters.set(cellCode, refNum);
514
+ bindCallbacks.get(cellCode).push({
515
+ callbackBody: bodyCode,
516
+ elementVars,
517
+ refNum,
518
+ paramName,
519
+ statementStart: stmtStart,
520
+ statementEnd: stmtEnd,
521
+ hasClosureVars,
522
+ });
523
+ }
506
524
 
507
- // Store bind callback info
508
- if (!bindCallbacks.has(cellCode)) {
509
- bindCallbacks.set(cellCode, []);
525
+ traverse(ast, {
526
+ // Handle: bind(cell, callback);
527
+ ExpressionStatement(path) {
528
+ const expr = path.node.expression;
529
+ if (!isBindCall(expr)) return;
530
+ processBindCall(expr, path.node.start, path.node.end);
531
+ },
532
+ // Handle: const _cleanup_N = bind(cell, callback);
533
+ VariableDeclaration(path) {
534
+ for (const decl of path.node.declarations) {
535
+ if (decl.init && isBindCall(decl.init)) {
536
+ processBindCall(decl.init, path.node.start, path.node.end);
537
+ }
510
538
  }
511
-
512
- bindCallbacks.get(cellCode).push({
513
- callbackBody: bodyCode,
514
- elementVars,
515
- refNum,
516
- paramName,
517
- statementStart: path.node.start,
518
- statementEnd: path.node.end,
519
- hasClosureVars,
520
- });
521
539
  },
522
540
  noScope: true,
523
541
  });