@fictjs/compiler 0.0.9 → 0.0.11

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 (3) hide show
  1. package/dist/index.cjs +308 -145
  2. package/dist/index.js +308 -145
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -18343,7 +18343,8 @@ function lowerNodeWithRegionContext(node, t2, ctx, declaredVars, regionCtx) {
18343
18343
  t2.blockStatement(conseqStmts),
18344
18344
  altStmts ? t2.blockStatement(altStmts) : null
18345
18345
  );
18346
- const shouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && expressionUsesTracked(node.test, ctx) && !statementHasEarlyExit(ifStmt, t2);
18346
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
18347
+ const shouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && !inNonReactiveScope && expressionUsesTracked(node.test, ctx) && !statementHasEarlyExit(ifStmt, t2);
18347
18348
  if (shouldWrapEffect) {
18348
18349
  ctx.helpersUsed.add("useEffect");
18349
18350
  ctx.needsCtx = true;
@@ -18571,31 +18572,53 @@ function lowerStructuredNodeForRegion(node, region, t2, ctx, declaredVars, regio
18571
18572
  return stmt ? [stmt] : [];
18572
18573
  }
18573
18574
  case "if": {
18574
- const consequent = lowerStructuredNodeForRegion(
18575
- node.consequent,
18576
- region,
18577
- t2,
18578
- ctx,
18579
- declaredVars,
18580
- regionCtx,
18581
- skipInstructions
18582
- );
18583
- const alternate = node.alternate ? lowerStructuredNodeForRegion(
18584
- node.alternate,
18585
- region,
18586
- t2,
18587
- ctx,
18588
- declaredVars,
18589
- regionCtx,
18590
- skipInstructions
18591
- ) : [];
18575
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
18576
+ const baseShouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && !inNonReactiveScope && expressionUsesTracked(node.test, ctx);
18577
+ const lowerChild = (child, forceNonReactive) => {
18578
+ if (!child) return [];
18579
+ if (!forceNonReactive) {
18580
+ return lowerStructuredNodeForRegion(
18581
+ child,
18582
+ region,
18583
+ t2,
18584
+ ctx,
18585
+ declaredVars,
18586
+ regionCtx,
18587
+ skipInstructions
18588
+ );
18589
+ }
18590
+ const prevDepth = ctx.nonReactiveScopeDepth ?? 0;
18591
+ ctx.nonReactiveScopeDepth = prevDepth + 1;
18592
+ try {
18593
+ return lowerStructuredNodeForRegion(
18594
+ child,
18595
+ region,
18596
+ t2,
18597
+ ctx,
18598
+ declaredVars,
18599
+ regionCtx,
18600
+ skipInstructions
18601
+ );
18602
+ } finally {
18603
+ ctx.nonReactiveScopeDepth = prevDepth;
18604
+ }
18605
+ };
18606
+ let consequent = lowerChild(node.consequent, baseShouldWrapEffect);
18607
+ let alternate = node.alternate ? lowerChild(node.alternate, baseShouldWrapEffect) : [];
18592
18608
  if (consequent.length === 0 && alternate.length === 0) return [];
18593
- const ifStmt = t2.ifStatement(
18609
+ const buildIfStmt = (cons, alt) => t2.ifStatement(
18594
18610
  lowerExpressionWithDeSSA(node.test, ctx),
18595
- t2.blockStatement(consequent),
18596
- alternate.length > 0 ? t2.blockStatement(alternate) : null
18611
+ t2.blockStatement(cons),
18612
+ alt.length > 0 ? t2.blockStatement(alt) : null
18597
18613
  );
18598
- const shouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && expressionUsesTracked(node.test, ctx) && !statementHasEarlyExit(ifStmt, t2);
18614
+ let ifStmt = buildIfStmt(consequent, alternate);
18615
+ const shouldWrapEffect = baseShouldWrapEffect && !statementHasEarlyExit(ifStmt, t2);
18616
+ if (!shouldWrapEffect && baseShouldWrapEffect) {
18617
+ consequent = lowerChild(node.consequent, false);
18618
+ alternate = node.alternate ? lowerChild(node.alternate, false) : [];
18619
+ if (consequent.length === 0 && alternate.length === 0) return [];
18620
+ ifStmt = buildIfStmt(consequent, alternate);
18621
+ }
18599
18622
  if (shouldWrapEffect) {
18600
18623
  ctx.helpersUsed.add("useEffect");
18601
18624
  ctx.needsCtx = true;
@@ -19622,7 +19645,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19622
19645
  (dep) => ctx.trackedVars.has(deSSAVarName(dep))
19623
19646
  );
19624
19647
  const usesTracked = expressionUsesTracked(instr.value, ctx);
19625
- const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && (usesTracked || hasTrackedControlDep);
19648
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
19649
+ const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && !inNonReactiveScope && (usesTracked || hasTrackedControlDep);
19626
19650
  if (shouldWrapExpr) {
19627
19651
  ctx.helpersUsed.add("useEffect");
19628
19652
  ctx.needsCtx = true;
@@ -21451,7 +21475,7 @@ function lowerExpression(expr, ctx, isAssigned = false) {
21451
21475
  ctx.expressionDepth = depth - 1;
21452
21476
  }
21453
21477
  }
21454
- function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21478
+ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21455
21479
  const { t: t2 } = ctx;
21456
21480
  const mapParams = (params) => params.map((p) => t2.identifier(deSSAVarName(p.name)));
21457
21481
  const withFunctionScope = (paramNames, fn) => {
@@ -21513,11 +21537,7 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21513
21537
  };
21514
21538
  const declared = new Set(paramIds.map((p) => p.name));
21515
21539
  return lowerStructuredNodeWithoutRegions(structured, t2, ctx, declared);
21516
- } catch (e) {
21517
- console.log(
21518
- "[DEBUG] Structurization failed, falling back to lowerBlocksToStatements via lowerInstruction",
21519
- e
21520
- );
21540
+ } catch {
21521
21541
  return lowerBlocksToStatements(blocks);
21522
21542
  }
21523
21543
  };
@@ -21696,12 +21716,10 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21696
21716
  case "ArrowFunction": {
21697
21717
  const paramIds = mapParams(expr.params);
21698
21718
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
21699
- return withFunctionScope(shadowed, () => {
21700
- if (isAssigned) {
21701
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) + 1;
21702
- }
21703
- let fn;
21704
- try {
21719
+ return withNonReactiveScope(
21720
+ ctx,
21721
+ () => withFunctionScope(shadowed, () => {
21722
+ let fn;
21705
21723
  if (expr.isExpression && !Array.isArray(expr.body)) {
21706
21724
  const { result: bodyExpr, cacheDeclarations } = withGetterCache(
21707
21725
  ctx,
@@ -21729,12 +21747,8 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21729
21747
  }
21730
21748
  fn.async = expr.isAsync ?? false;
21731
21749
  return fn;
21732
- } finally {
21733
- if (isAssigned) {
21734
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) - 1;
21735
- }
21736
- }
21737
- });
21750
+ })
21751
+ );
21738
21752
  }
21739
21753
  case "FunctionExpression": {
21740
21754
  const paramIds = mapParams(expr.params);
@@ -22746,114 +22760,151 @@ function lowerIntrinsicElement(jsx, ctx) {
22746
22760
  for (const binding of bindings) {
22747
22761
  const targetId = resolveHIRBindingPath(binding.path, nodeCache, statements, ctx);
22748
22762
  if (binding.type === "event" && binding.expr && binding.name) {
22749
- const shouldWrapHandler = isExpressionReactive(binding.expr, ctx);
22750
- const prevWrapTracked = ctx.wrapTrackedExpressions;
22751
- ctx.wrapTrackedExpressions = false;
22752
- const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion, {
22753
- skipHookAccessors: true,
22754
- skipRegionRootOverride: true
22755
- });
22756
- ctx.wrapTrackedExpressions = prevWrapTracked;
22757
- const eventParam = t2.identifier("_e");
22758
- const isFn = t2.isArrowFunctionExpression(valueExpr) || t2.isFunctionExpression(valueExpr);
22759
- const ensureHandlerParam = (fn) => {
22760
- if (t2.isArrowFunctionExpression(fn)) {
22761
- if (fn.params.length > 0) return fn;
22762
- return t2.arrowFunctionExpression([eventParam], fn.body, fn.async);
22763
- }
22764
- if (t2.isFunctionExpression(fn)) {
22765
- if (fn.params.length > 0) return fn;
22766
- return t2.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
22767
- }
22768
- return t2.arrowFunctionExpression(
22769
- [eventParam],
22770
- t2.callExpression(fn, [eventParam])
22771
- );
22772
- };
22773
- const handlerExpr = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([], valueExpr) : ensureHandlerParam(valueExpr);
22774
22763
  const eventName = binding.name;
22775
22764
  const hasEventOptions = binding.eventOptions && (binding.eventOptions.capture || binding.eventOptions.passive || binding.eventOptions.once);
22776
22765
  const isDelegated = DelegatedEvents.has(eventName) && !hasEventOptions;
22777
- const dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t2) : null;
22778
- if (isDelegated) {
22766
+ const hirDataBinding = isDelegated && binding.expr ? extractDelegatedEventDataFromHIR(binding.expr, ctx) : null;
22767
+ if (hirDataBinding) {
22779
22768
  ctx.delegatedEventsUsed?.add(eventName);
22780
- const finalHandler = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([eventParam], t2.callExpression(valueExpr, [eventParam])) : handlerExpr;
22781
- const normalizeHandler = (expr) => {
22782
- if (t2.isCallExpression(expr) && (t2.isIdentifier(expr.callee) || t2.isMemberExpression(expr.callee))) {
22783
- return expr.callee;
22784
- }
22785
- return expr;
22786
- };
22787
- const normalizedDataHandler = dataBinding !== null ? normalizeHandler(dataBinding?.handler ?? handlerExpr) : null;
22788
- const dataForDelegate = dataBinding?.data && (t2.isArrowFunctionExpression(dataBinding.data) || t2.isFunctionExpression(dataBinding.data) ? dataBinding.data : t2.arrowFunctionExpression([], dataBinding.data));
22789
- const handlerForDelegate = normalizedDataHandler ?? (dataBinding ? normalizeHandler(handlerExpr) : finalHandler);
22790
- const handlerIsCallableExpr = t2.isArrowFunctionExpression(handlerForDelegate) || t2.isFunctionExpression(handlerForDelegate) || t2.isIdentifier(handlerForDelegate) || t2.isMemberExpression(handlerForDelegate);
22791
- let handlerToAssign = handlerIsCallableExpr ? handlerForDelegate : t2.arrowFunctionExpression([eventParam], handlerForDelegate);
22792
- if (dataForDelegate) {
22793
- let payloadExpr;
22794
- if (t2.isArrowFunctionExpression(dataForDelegate) && dataForDelegate.params.length === 0) {
22795
- payloadExpr = t2.isBlockStatement(dataForDelegate.body) ? t2.callExpression(t2.arrowFunctionExpression([], dataForDelegate.body), []) : dataForDelegate.body;
22796
- } else {
22797
- payloadExpr = t2.callExpression(dataForDelegate, []);
22798
- }
22799
- handlerToAssign = t2.arrowFunctionExpression(
22800
- [eventParam],
22801
- t2.callExpression(handlerForDelegate, [payloadExpr])
22802
- );
22803
- }
22769
+ const handlerExpr = lowerExpression(hirDataBinding.handler, ctx);
22770
+ const dataExpr = lowerDomExpression(hirDataBinding.data, ctx, containingRegion, {
22771
+ skipHookAccessors: false,
22772
+ skipRegionRootOverride: true
22773
+ });
22774
+ const dataParam = t2.identifier("__data");
22775
+ const eventParam = t2.identifier("_e");
22776
+ const wrappedHandler = t2.arrowFunctionExpression(
22777
+ [dataParam, eventParam],
22778
+ t2.callExpression(handlerExpr, [dataParam])
22779
+ );
22804
22780
  statements.push(
22805
22781
  t2.expressionStatement(
22806
22782
  t2.assignmentExpression(
22807
22783
  "=",
22808
22784
  t2.memberExpression(targetId, t2.identifier(`$$${eventName}`)),
22809
- handlerToAssign
22785
+ wrappedHandler
22810
22786
  )
22811
22787
  )
22812
22788
  );
22813
- if (dataForDelegate) {
22789
+ const dataGetter = t2.arrowFunctionExpression([], dataExpr);
22790
+ statements.push(
22791
+ t2.expressionStatement(
22792
+ t2.assignmentExpression(
22793
+ "=",
22794
+ t2.memberExpression(targetId, t2.identifier(`$$${eventName}Data`)),
22795
+ dataGetter
22796
+ )
22797
+ )
22798
+ );
22799
+ } else {
22800
+ const shouldWrapHandler = isExpressionReactive(binding.expr, ctx);
22801
+ const prevWrapTracked = ctx.wrapTrackedExpressions;
22802
+ ctx.wrapTrackedExpressions = false;
22803
+ const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion, {
22804
+ skipHookAccessors: true,
22805
+ skipRegionRootOverride: true
22806
+ });
22807
+ ctx.wrapTrackedExpressions = prevWrapTracked;
22808
+ const eventParam = t2.identifier("_e");
22809
+ const isFn = t2.isArrowFunctionExpression(valueExpr) || t2.isFunctionExpression(valueExpr);
22810
+ const ensureHandlerParam = (fn) => {
22811
+ if (t2.isArrowFunctionExpression(fn)) {
22812
+ if (fn.params.length > 0) return fn;
22813
+ return t2.arrowFunctionExpression([eventParam], fn.body, fn.async);
22814
+ }
22815
+ if (t2.isFunctionExpression(fn)) {
22816
+ if (fn.params.length > 0) return fn;
22817
+ return t2.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
22818
+ }
22819
+ return t2.arrowFunctionExpression(
22820
+ [eventParam],
22821
+ t2.callExpression(fn, [eventParam])
22822
+ );
22823
+ };
22824
+ const handlerExpr = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([], valueExpr) : ensureHandlerParam(valueExpr);
22825
+ const dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t2) : null;
22826
+ if (isDelegated) {
22827
+ ctx.delegatedEventsUsed?.add(eventName);
22828
+ const finalHandler = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([eventParam], t2.callExpression(valueExpr, [eventParam])) : handlerExpr;
22829
+ const normalizeHandler = (expr) => {
22830
+ if (t2.isCallExpression(expr) && (t2.isIdentifier(expr.callee) || t2.isMemberExpression(expr.callee))) {
22831
+ return expr.callee;
22832
+ }
22833
+ return expr;
22834
+ };
22835
+ const normalizedDataHandler = dataBinding !== null ? normalizeHandler(
22836
+ dataBinding?.handler ?? handlerExpr
22837
+ ) : null;
22838
+ const dataForDelegate = dataBinding?.data && (t2.isArrowFunctionExpression(dataBinding.data) || t2.isFunctionExpression(dataBinding.data) ? dataBinding.data : t2.arrowFunctionExpression([], dataBinding.data));
22839
+ const handlerForDelegate = normalizedDataHandler ?? (dataBinding ? normalizeHandler(handlerExpr) : finalHandler);
22840
+ const handlerIsCallableExpr = t2.isArrowFunctionExpression(handlerForDelegate) || t2.isFunctionExpression(handlerForDelegate) || t2.isIdentifier(handlerForDelegate) || t2.isMemberExpression(handlerForDelegate);
22841
+ let handlerToAssign = handlerIsCallableExpr ? handlerForDelegate : t2.arrowFunctionExpression([eventParam], handlerForDelegate);
22842
+ if (dataForDelegate) {
22843
+ let payloadExpr;
22844
+ if (t2.isArrowFunctionExpression(dataForDelegate) && dataForDelegate.params.length === 0) {
22845
+ payloadExpr = t2.isBlockStatement(dataForDelegate.body) ? t2.callExpression(t2.arrowFunctionExpression([], dataForDelegate.body), []) : dataForDelegate.body;
22846
+ } else {
22847
+ payloadExpr = t2.callExpression(dataForDelegate, []);
22848
+ }
22849
+ handlerToAssign = t2.arrowFunctionExpression(
22850
+ [eventParam],
22851
+ t2.callExpression(handlerForDelegate, [payloadExpr])
22852
+ );
22853
+ }
22814
22854
  statements.push(
22815
22855
  t2.expressionStatement(
22816
22856
  t2.assignmentExpression(
22817
22857
  "=",
22818
- t2.memberExpression(targetId, t2.identifier(`$$${eventName}Data`)),
22819
- dataForDelegate
22858
+ t2.memberExpression(targetId, t2.identifier(`$$${eventName}`)),
22859
+ handlerToAssign
22820
22860
  )
22821
22861
  )
22822
22862
  );
22823
- }
22824
- } else {
22825
- ctx.helpersUsed.add("bindEvent");
22826
- ctx.helpersUsed.add("onDestroy");
22827
- const cleanupId = genTemp(ctx, "evt");
22828
- const args = [
22829
- targetId,
22830
- t2.stringLiteral(eventName),
22831
- handlerExpr
22832
- ];
22833
- if (hasEventOptions && binding.eventOptions) {
22834
- const optionProps = [];
22835
- if (binding.eventOptions.capture) {
22836
- optionProps.push(t2.objectProperty(t2.identifier("capture"), t2.booleanLiteral(true)));
22837
- }
22838
- if (binding.eventOptions.passive) {
22839
- optionProps.push(t2.objectProperty(t2.identifier("passive"), t2.booleanLiteral(true)));
22863
+ if (dataForDelegate) {
22864
+ statements.push(
22865
+ t2.expressionStatement(
22866
+ t2.assignmentExpression(
22867
+ "=",
22868
+ t2.memberExpression(targetId, t2.identifier(`$$${eventName}Data`)),
22869
+ dataForDelegate
22870
+ )
22871
+ )
22872
+ );
22840
22873
  }
22841
- if (binding.eventOptions.once) {
22842
- optionProps.push(t2.objectProperty(t2.identifier("once"), t2.booleanLiteral(true)));
22874
+ } else {
22875
+ ctx.helpersUsed.add("bindEvent");
22876
+ ctx.helpersUsed.add("onDestroy");
22877
+ const cleanupId = genTemp(ctx, "evt");
22878
+ const args = [
22879
+ targetId,
22880
+ t2.stringLiteral(eventName),
22881
+ handlerExpr
22882
+ ];
22883
+ if (hasEventOptions && binding.eventOptions) {
22884
+ const optionProps = [];
22885
+ if (binding.eventOptions.capture) {
22886
+ optionProps.push(t2.objectProperty(t2.identifier("capture"), t2.booleanLiteral(true)));
22887
+ }
22888
+ if (binding.eventOptions.passive) {
22889
+ optionProps.push(t2.objectProperty(t2.identifier("passive"), t2.booleanLiteral(true)));
22890
+ }
22891
+ if (binding.eventOptions.once) {
22892
+ optionProps.push(t2.objectProperty(t2.identifier("once"), t2.booleanLiteral(true)));
22893
+ }
22894
+ args.push(t2.objectExpression(optionProps));
22843
22895
  }
22844
- args.push(t2.objectExpression(optionProps));
22845
- }
22846
- statements.push(
22847
- t2.variableDeclaration("const", [
22848
- t2.variableDeclarator(
22849
- cleanupId,
22850
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindEvent), args)
22896
+ statements.push(
22897
+ t2.variableDeclaration("const", [
22898
+ t2.variableDeclarator(
22899
+ cleanupId,
22900
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindEvent), args)
22901
+ )
22902
+ ]),
22903
+ t2.expressionStatement(
22904
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.onDestroy), [cleanupId])
22851
22905
  )
22852
- ]),
22853
- t2.expressionStatement(
22854
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.onDestroy), [cleanupId])
22855
- )
22856
- );
22906
+ );
22907
+ }
22857
22908
  }
22858
22909
  } else if (binding.type === "attr" && binding.name) {
22859
22910
  const attrName = binding.name;
@@ -22915,16 +22966,28 @@ function lowerIntrinsicElement(jsx, ctx) {
22915
22966
  t2.expressionStatement(lowerDomExpression(binding.expr, ctx, containingRegion))
22916
22967
  );
22917
22968
  } else if (binding.type === "text" && binding.expr) {
22918
- ctx.helpersUsed.add("bindText");
22919
22969
  const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion);
22920
- statements.push(
22921
- t2.expressionStatement(
22922
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22923
- targetId,
22924
- t2.arrowFunctionExpression([], valueExpr)
22925
- ])
22926
- )
22927
- );
22970
+ if (isExpressionReactive(binding.expr, ctx)) {
22971
+ ctx.helpersUsed.add("bindText");
22972
+ statements.push(
22973
+ t2.expressionStatement(
22974
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22975
+ targetId,
22976
+ t2.arrowFunctionExpression([], valueExpr)
22977
+ ])
22978
+ )
22979
+ );
22980
+ } else {
22981
+ statements.push(
22982
+ t2.expressionStatement(
22983
+ t2.assignmentExpression(
22984
+ "=",
22985
+ t2.memberExpression(targetId, t2.identifier("data")),
22986
+ t2.callExpression(t2.identifier("String"), [valueExpr])
22987
+ )
22988
+ )
22989
+ );
22990
+ }
22928
22991
  } else if (binding.type === "child" && binding.expr) {
22929
22992
  emitHIRChildBinding(targetId, binding.expr, statements, ctx, containingRegion);
22930
22993
  }
@@ -23228,6 +23291,82 @@ function extractDelegatedEventData(expr, t2) {
23228
23291
  data: dataArg && t2.isExpression(dataArg) ? dataArg : void 0
23229
23292
  };
23230
23293
  }
23294
+ function extractDelegatedEventDataFromHIR(expr, ctx) {
23295
+ if (expr.kind !== "ArrowFunction" && expr.kind !== "FunctionExpression") {
23296
+ return null;
23297
+ }
23298
+ let bodyExpr = null;
23299
+ if (expr.kind === "ArrowFunction") {
23300
+ if (expr.isExpression && !Array.isArray(expr.body)) {
23301
+ bodyExpr = expr.body;
23302
+ }
23303
+ }
23304
+ if (!bodyExpr || bodyExpr.kind !== "CallExpression") {
23305
+ return null;
23306
+ }
23307
+ const callee = bodyExpr.callee;
23308
+ if (callee.kind !== "Identifier") {
23309
+ return null;
23310
+ }
23311
+ if (bodyExpr.arguments.length !== 1) {
23312
+ return null;
23313
+ }
23314
+ if (callee.kind === "Identifier") {
23315
+ const handlerName = deSSAVarName(callee.name);
23316
+ const isTrackedAccessor = ctx.signalVars?.has(handlerName) || ctx.memoVars?.has(handlerName) || ctx.aliasVars?.has(handlerName);
23317
+ if (isTrackedAccessor) {
23318
+ return null;
23319
+ }
23320
+ }
23321
+ const paramNames = new Set(expr.params.map((p) => p.name));
23322
+ const dataExpr = bodyExpr.arguments[0];
23323
+ if (!dataExpr) {
23324
+ return null;
23325
+ }
23326
+ if (hirExpressionUsesIdentifiers(dataExpr, paramNames)) {
23327
+ return null;
23328
+ }
23329
+ return {
23330
+ handler: callee,
23331
+ data: dataExpr
23332
+ };
23333
+ }
23334
+ function hirExpressionUsesIdentifiers(expr, names) {
23335
+ if (expr.kind === "Identifier") {
23336
+ return names.has(deSSAVarName(expr.name));
23337
+ }
23338
+ switch (expr.kind) {
23339
+ case "BinaryExpression":
23340
+ case "LogicalExpression":
23341
+ return hirExpressionUsesIdentifiers(expr.left, names) || hirExpressionUsesIdentifiers(expr.right, names);
23342
+ case "UnaryExpression":
23343
+ return hirExpressionUsesIdentifiers(expr.argument, names);
23344
+ case "ConditionalExpression":
23345
+ return hirExpressionUsesIdentifiers(expr.test, names) || hirExpressionUsesIdentifiers(expr.consequent, names) || hirExpressionUsesIdentifiers(expr.alternate, names);
23346
+ case "CallExpression":
23347
+ case "OptionalCallExpression":
23348
+ return hirExpressionUsesIdentifiers(expr.callee, names) || expr.arguments.some((arg) => hirExpressionUsesIdentifiers(arg, names));
23349
+ case "MemberExpression":
23350
+ case "OptionalMemberExpression":
23351
+ return hirExpressionUsesIdentifiers(expr.object, names) || expr.computed && hirExpressionUsesIdentifiers(expr.property, names);
23352
+ case "ArrayExpression":
23353
+ return expr.elements.some((el) => el && hirExpressionUsesIdentifiers(el, names));
23354
+ case "ObjectExpression":
23355
+ return expr.properties.some((prop) => {
23356
+ if (prop.kind === "SpreadElement") {
23357
+ return hirExpressionUsesIdentifiers(prop.argument, names);
23358
+ }
23359
+ return hirExpressionUsesIdentifiers(prop.key, names) || hirExpressionUsesIdentifiers(prop.value, names);
23360
+ });
23361
+ case "TemplateLiteral":
23362
+ return expr.expressions.some((e) => hirExpressionUsesIdentifiers(e, names));
23363
+ case "ArrowFunction":
23364
+ case "FunctionExpression":
23365
+ return false;
23366
+ default:
23367
+ return false;
23368
+ }
23369
+ }
23231
23370
  function getTrackedCallIdentifier(expr, ctx, itemParamName) {
23232
23371
  if (ctx.t.isCallExpression(expr) && ctx.t.isIdentifier(expr.callee)) {
23233
23372
  if (expr.arguments.length !== 0) return null;
@@ -23238,8 +23377,13 @@ function getTrackedCallIdentifier(expr, ctx, itemParamName) {
23238
23377
  }
23239
23378
  return null;
23240
23379
  }
23241
- function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23380
+ function rewriteSelectorExpression(expr, itemParamName, keyParamName, getSelectorId, ctx) {
23242
23381
  const { t: t2 } = ctx;
23382
+ const usesParamIdentifier = (e) => {
23383
+ if (expressionUsesIdentifier(e, itemParamName, t2)) return true;
23384
+ if (keyParamName && expressionUsesIdentifier(e, keyParamName, t2)) return true;
23385
+ return false;
23386
+ };
23243
23387
  if (t2.isBinaryExpression(expr) && (expr.operator === "===" || expr.operator === "==")) {
23244
23388
  const leftTracked = getTrackedCallIdentifier(
23245
23389
  expr.left,
@@ -23251,7 +23395,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23251
23395
  ctx,
23252
23396
  itemParamName
23253
23397
  );
23254
- if (leftTracked && expressionUsesIdentifier(expr.right, itemParamName, t2)) {
23398
+ if (leftTracked && usesParamIdentifier(expr.right)) {
23255
23399
  return {
23256
23400
  expr: t2.callExpression(getSelectorId(leftTracked), [
23257
23401
  expr.right
@@ -23259,7 +23403,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23259
23403
  changed: true
23260
23404
  };
23261
23405
  }
23262
- if (rightTracked && expressionUsesIdentifier(expr.left, itemParamName, t2)) {
23406
+ if (rightTracked && usesParamIdentifier(expr.left)) {
23263
23407
  return {
23264
23408
  expr: t2.callExpression(getSelectorId(rightTracked), [
23265
23409
  expr.left
@@ -23270,7 +23414,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23270
23414
  }
23271
23415
  let changed = false;
23272
23416
  const rewrite = (node) => {
23273
- const result = rewriteSelectorExpression(node, itemParamName, getSelectorId, ctx);
23417
+ const result = rewriteSelectorExpression(node, itemParamName, keyParamName, getSelectorId, ctx);
23274
23418
  if (result.changed) changed = true;
23275
23419
  return result.expr;
23276
23420
  };
@@ -23331,7 +23475,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23331
23475
  }
23332
23476
  return { expr, changed };
23333
23477
  }
23334
- function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23478
+ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statements, ctx) {
23335
23479
  const { t: t2 } = ctx;
23336
23480
  if (!itemParamName) return;
23337
23481
  if (!t2.isArrowFunctionExpression(callbackExpr) && !t2.isFunctionExpression(callbackExpr)) return;
@@ -23347,7 +23491,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23347
23491
  if (t2.isBlockStatement(fn.body)) {
23348
23492
  for (const stmt of fn.body.body) {
23349
23493
  if (t2.isReturnStatement(stmt) && stmt.argument && t2.isExpression(stmt.argument)) {
23350
- const result = rewriteSelectorExpression(stmt.argument, itemParamName, getSelectorId, ctx);
23494
+ const result = rewriteSelectorExpression(
23495
+ stmt.argument,
23496
+ itemParamName,
23497
+ keyParamName,
23498
+ getSelectorId,
23499
+ ctx
23500
+ );
23351
23501
  if (result.changed) {
23352
23502
  stmt.argument = result.expr;
23353
23503
  }
@@ -23356,7 +23506,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23356
23506
  return;
23357
23507
  }
23358
23508
  if (t2.isExpression(fn.body)) {
23359
- const result = rewriteSelectorExpression(fn.body, itemParamName, getSelectorId, ctx);
23509
+ const result = rewriteSelectorExpression(
23510
+ fn.body,
23511
+ itemParamName,
23512
+ keyParamName,
23513
+ getSelectorId,
23514
+ ctx
23515
+ );
23360
23516
  if (result.changed) {
23361
23517
  fn.body = result.expr;
23362
23518
  }
@@ -23520,7 +23676,14 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23520
23676
  const listId = genTemp(ctx, "list");
23521
23677
  if (isKeyed) {
23522
23678
  const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : null : null;
23523
- applySelectorHoist(callbackExpr, itemParamName, statements, ctx);
23679
+ const keyParamName = ctx.listKeyParamName ?? null;
23680
+ applySelectorHoist(
23681
+ callbackExpr,
23682
+ itemParamName,
23683
+ keyParamName,
23684
+ statements,
23685
+ ctx
23686
+ );
23524
23687
  }
23525
23688
  if (isKeyed && keyExpr) {
23526
23689
  let keyExprAst = lowerExpression(keyExpr, ctx);
package/dist/index.js CHANGED
@@ -18331,7 +18331,8 @@ function lowerNodeWithRegionContext(node, t2, ctx, declaredVars, regionCtx) {
18331
18331
  t2.blockStatement(conseqStmts),
18332
18332
  altStmts ? t2.blockStatement(altStmts) : null
18333
18333
  );
18334
- const shouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && expressionUsesTracked(node.test, ctx) && !statementHasEarlyExit(ifStmt, t2);
18334
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
18335
+ const shouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && !inNonReactiveScope && expressionUsesTracked(node.test, ctx) && !statementHasEarlyExit(ifStmt, t2);
18335
18336
  if (shouldWrapEffect) {
18336
18337
  ctx.helpersUsed.add("useEffect");
18337
18338
  ctx.needsCtx = true;
@@ -18559,31 +18560,53 @@ function lowerStructuredNodeForRegion(node, region, t2, ctx, declaredVars, regio
18559
18560
  return stmt ? [stmt] : [];
18560
18561
  }
18561
18562
  case "if": {
18562
- const consequent = lowerStructuredNodeForRegion(
18563
- node.consequent,
18564
- region,
18565
- t2,
18566
- ctx,
18567
- declaredVars,
18568
- regionCtx,
18569
- skipInstructions
18570
- );
18571
- const alternate = node.alternate ? lowerStructuredNodeForRegion(
18572
- node.alternate,
18573
- region,
18574
- t2,
18575
- ctx,
18576
- declaredVars,
18577
- regionCtx,
18578
- skipInstructions
18579
- ) : [];
18563
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
18564
+ const baseShouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && !inNonReactiveScope && expressionUsesTracked(node.test, ctx);
18565
+ const lowerChild = (child, forceNonReactive) => {
18566
+ if (!child) return [];
18567
+ if (!forceNonReactive) {
18568
+ return lowerStructuredNodeForRegion(
18569
+ child,
18570
+ region,
18571
+ t2,
18572
+ ctx,
18573
+ declaredVars,
18574
+ regionCtx,
18575
+ skipInstructions
18576
+ );
18577
+ }
18578
+ const prevDepth = ctx.nonReactiveScopeDepth ?? 0;
18579
+ ctx.nonReactiveScopeDepth = prevDepth + 1;
18580
+ try {
18581
+ return lowerStructuredNodeForRegion(
18582
+ child,
18583
+ region,
18584
+ t2,
18585
+ ctx,
18586
+ declaredVars,
18587
+ regionCtx,
18588
+ skipInstructions
18589
+ );
18590
+ } finally {
18591
+ ctx.nonReactiveScopeDepth = prevDepth;
18592
+ }
18593
+ };
18594
+ let consequent = lowerChild(node.consequent, baseShouldWrapEffect);
18595
+ let alternate = node.alternate ? lowerChild(node.alternate, baseShouldWrapEffect) : [];
18580
18596
  if (consequent.length === 0 && alternate.length === 0) return [];
18581
- const ifStmt = t2.ifStatement(
18597
+ const buildIfStmt = (cons, alt) => t2.ifStatement(
18582
18598
  lowerExpressionWithDeSSA(node.test, ctx),
18583
- t2.blockStatement(consequent),
18584
- alternate.length > 0 ? t2.blockStatement(alternate) : null
18599
+ t2.blockStatement(cons),
18600
+ alt.length > 0 ? t2.blockStatement(alt) : null
18585
18601
  );
18586
- const shouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && expressionUsesTracked(node.test, ctx) && !statementHasEarlyExit(ifStmt, t2);
18602
+ let ifStmt = buildIfStmt(consequent, alternate);
18603
+ const shouldWrapEffect = baseShouldWrapEffect && !statementHasEarlyExit(ifStmt, t2);
18604
+ if (!shouldWrapEffect && baseShouldWrapEffect) {
18605
+ consequent = lowerChild(node.consequent, false);
18606
+ alternate = node.alternate ? lowerChild(node.alternate, false) : [];
18607
+ if (consequent.length === 0 && alternate.length === 0) return [];
18608
+ ifStmt = buildIfStmt(consequent, alternate);
18609
+ }
18587
18610
  if (shouldWrapEffect) {
18588
18611
  ctx.helpersUsed.add("useEffect");
18589
18612
  ctx.needsCtx = true;
@@ -19610,7 +19633,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19610
19633
  (dep) => ctx.trackedVars.has(deSSAVarName(dep))
19611
19634
  );
19612
19635
  const usesTracked = expressionUsesTracked(instr.value, ctx);
19613
- const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && (usesTracked || hasTrackedControlDep);
19636
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
19637
+ const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && !inNonReactiveScope && (usesTracked || hasTrackedControlDep);
19614
19638
  if (shouldWrapExpr) {
19615
19639
  ctx.helpersUsed.add("useEffect");
19616
19640
  ctx.needsCtx = true;
@@ -21439,7 +21463,7 @@ function lowerExpression(expr, ctx, isAssigned = false) {
21439
21463
  ctx.expressionDepth = depth - 1;
21440
21464
  }
21441
21465
  }
21442
- function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21466
+ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21443
21467
  const { t: t2 } = ctx;
21444
21468
  const mapParams = (params) => params.map((p) => t2.identifier(deSSAVarName(p.name)));
21445
21469
  const withFunctionScope = (paramNames, fn) => {
@@ -21501,11 +21525,7 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21501
21525
  };
21502
21526
  const declared = new Set(paramIds.map((p) => p.name));
21503
21527
  return lowerStructuredNodeWithoutRegions(structured, t2, ctx, declared);
21504
- } catch (e) {
21505
- console.log(
21506
- "[DEBUG] Structurization failed, falling back to lowerBlocksToStatements via lowerInstruction",
21507
- e
21508
- );
21528
+ } catch {
21509
21529
  return lowerBlocksToStatements(blocks);
21510
21530
  }
21511
21531
  };
@@ -21684,12 +21704,10 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21684
21704
  case "ArrowFunction": {
21685
21705
  const paramIds = mapParams(expr.params);
21686
21706
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
21687
- return withFunctionScope(shadowed, () => {
21688
- if (isAssigned) {
21689
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) + 1;
21690
- }
21691
- let fn;
21692
- try {
21707
+ return withNonReactiveScope(
21708
+ ctx,
21709
+ () => withFunctionScope(shadowed, () => {
21710
+ let fn;
21693
21711
  if (expr.isExpression && !Array.isArray(expr.body)) {
21694
21712
  const { result: bodyExpr, cacheDeclarations } = withGetterCache(
21695
21713
  ctx,
@@ -21717,12 +21735,8 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21717
21735
  }
21718
21736
  fn.async = expr.isAsync ?? false;
21719
21737
  return fn;
21720
- } finally {
21721
- if (isAssigned) {
21722
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) - 1;
21723
- }
21724
- }
21725
- });
21738
+ })
21739
+ );
21726
21740
  }
21727
21741
  case "FunctionExpression": {
21728
21742
  const paramIds = mapParams(expr.params);
@@ -22734,114 +22748,151 @@ function lowerIntrinsicElement(jsx, ctx) {
22734
22748
  for (const binding of bindings) {
22735
22749
  const targetId = resolveHIRBindingPath(binding.path, nodeCache, statements, ctx);
22736
22750
  if (binding.type === "event" && binding.expr && binding.name) {
22737
- const shouldWrapHandler = isExpressionReactive(binding.expr, ctx);
22738
- const prevWrapTracked = ctx.wrapTrackedExpressions;
22739
- ctx.wrapTrackedExpressions = false;
22740
- const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion, {
22741
- skipHookAccessors: true,
22742
- skipRegionRootOverride: true
22743
- });
22744
- ctx.wrapTrackedExpressions = prevWrapTracked;
22745
- const eventParam = t2.identifier("_e");
22746
- const isFn = t2.isArrowFunctionExpression(valueExpr) || t2.isFunctionExpression(valueExpr);
22747
- const ensureHandlerParam = (fn) => {
22748
- if (t2.isArrowFunctionExpression(fn)) {
22749
- if (fn.params.length > 0) return fn;
22750
- return t2.arrowFunctionExpression([eventParam], fn.body, fn.async);
22751
- }
22752
- if (t2.isFunctionExpression(fn)) {
22753
- if (fn.params.length > 0) return fn;
22754
- return t2.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
22755
- }
22756
- return t2.arrowFunctionExpression(
22757
- [eventParam],
22758
- t2.callExpression(fn, [eventParam])
22759
- );
22760
- };
22761
- const handlerExpr = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([], valueExpr) : ensureHandlerParam(valueExpr);
22762
22751
  const eventName = binding.name;
22763
22752
  const hasEventOptions = binding.eventOptions && (binding.eventOptions.capture || binding.eventOptions.passive || binding.eventOptions.once);
22764
22753
  const isDelegated = DelegatedEvents.has(eventName) && !hasEventOptions;
22765
- const dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t2) : null;
22766
- if (isDelegated) {
22754
+ const hirDataBinding = isDelegated && binding.expr ? extractDelegatedEventDataFromHIR(binding.expr, ctx) : null;
22755
+ if (hirDataBinding) {
22767
22756
  ctx.delegatedEventsUsed?.add(eventName);
22768
- const finalHandler = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([eventParam], t2.callExpression(valueExpr, [eventParam])) : handlerExpr;
22769
- const normalizeHandler = (expr) => {
22770
- if (t2.isCallExpression(expr) && (t2.isIdentifier(expr.callee) || t2.isMemberExpression(expr.callee))) {
22771
- return expr.callee;
22772
- }
22773
- return expr;
22774
- };
22775
- const normalizedDataHandler = dataBinding !== null ? normalizeHandler(dataBinding?.handler ?? handlerExpr) : null;
22776
- const dataForDelegate = dataBinding?.data && (t2.isArrowFunctionExpression(dataBinding.data) || t2.isFunctionExpression(dataBinding.data) ? dataBinding.data : t2.arrowFunctionExpression([], dataBinding.data));
22777
- const handlerForDelegate = normalizedDataHandler ?? (dataBinding ? normalizeHandler(handlerExpr) : finalHandler);
22778
- const handlerIsCallableExpr = t2.isArrowFunctionExpression(handlerForDelegate) || t2.isFunctionExpression(handlerForDelegate) || t2.isIdentifier(handlerForDelegate) || t2.isMemberExpression(handlerForDelegate);
22779
- let handlerToAssign = handlerIsCallableExpr ? handlerForDelegate : t2.arrowFunctionExpression([eventParam], handlerForDelegate);
22780
- if (dataForDelegate) {
22781
- let payloadExpr;
22782
- if (t2.isArrowFunctionExpression(dataForDelegate) && dataForDelegate.params.length === 0) {
22783
- payloadExpr = t2.isBlockStatement(dataForDelegate.body) ? t2.callExpression(t2.arrowFunctionExpression([], dataForDelegate.body), []) : dataForDelegate.body;
22784
- } else {
22785
- payloadExpr = t2.callExpression(dataForDelegate, []);
22786
- }
22787
- handlerToAssign = t2.arrowFunctionExpression(
22788
- [eventParam],
22789
- t2.callExpression(handlerForDelegate, [payloadExpr])
22790
- );
22791
- }
22757
+ const handlerExpr = lowerExpression(hirDataBinding.handler, ctx);
22758
+ const dataExpr = lowerDomExpression(hirDataBinding.data, ctx, containingRegion, {
22759
+ skipHookAccessors: false,
22760
+ skipRegionRootOverride: true
22761
+ });
22762
+ const dataParam = t2.identifier("__data");
22763
+ const eventParam = t2.identifier("_e");
22764
+ const wrappedHandler = t2.arrowFunctionExpression(
22765
+ [dataParam, eventParam],
22766
+ t2.callExpression(handlerExpr, [dataParam])
22767
+ );
22792
22768
  statements.push(
22793
22769
  t2.expressionStatement(
22794
22770
  t2.assignmentExpression(
22795
22771
  "=",
22796
22772
  t2.memberExpression(targetId, t2.identifier(`$$${eventName}`)),
22797
- handlerToAssign
22773
+ wrappedHandler
22798
22774
  )
22799
22775
  )
22800
22776
  );
22801
- if (dataForDelegate) {
22777
+ const dataGetter = t2.arrowFunctionExpression([], dataExpr);
22778
+ statements.push(
22779
+ t2.expressionStatement(
22780
+ t2.assignmentExpression(
22781
+ "=",
22782
+ t2.memberExpression(targetId, t2.identifier(`$$${eventName}Data`)),
22783
+ dataGetter
22784
+ )
22785
+ )
22786
+ );
22787
+ } else {
22788
+ const shouldWrapHandler = isExpressionReactive(binding.expr, ctx);
22789
+ const prevWrapTracked = ctx.wrapTrackedExpressions;
22790
+ ctx.wrapTrackedExpressions = false;
22791
+ const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion, {
22792
+ skipHookAccessors: true,
22793
+ skipRegionRootOverride: true
22794
+ });
22795
+ ctx.wrapTrackedExpressions = prevWrapTracked;
22796
+ const eventParam = t2.identifier("_e");
22797
+ const isFn = t2.isArrowFunctionExpression(valueExpr) || t2.isFunctionExpression(valueExpr);
22798
+ const ensureHandlerParam = (fn) => {
22799
+ if (t2.isArrowFunctionExpression(fn)) {
22800
+ if (fn.params.length > 0) return fn;
22801
+ return t2.arrowFunctionExpression([eventParam], fn.body, fn.async);
22802
+ }
22803
+ if (t2.isFunctionExpression(fn)) {
22804
+ if (fn.params.length > 0) return fn;
22805
+ return t2.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
22806
+ }
22807
+ return t2.arrowFunctionExpression(
22808
+ [eventParam],
22809
+ t2.callExpression(fn, [eventParam])
22810
+ );
22811
+ };
22812
+ const handlerExpr = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([], valueExpr) : ensureHandlerParam(valueExpr);
22813
+ const dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t2) : null;
22814
+ if (isDelegated) {
22815
+ ctx.delegatedEventsUsed?.add(eventName);
22816
+ const finalHandler = !isFn && shouldWrapHandler ? t2.arrowFunctionExpression([eventParam], t2.callExpression(valueExpr, [eventParam])) : handlerExpr;
22817
+ const normalizeHandler = (expr) => {
22818
+ if (t2.isCallExpression(expr) && (t2.isIdentifier(expr.callee) || t2.isMemberExpression(expr.callee))) {
22819
+ return expr.callee;
22820
+ }
22821
+ return expr;
22822
+ };
22823
+ const normalizedDataHandler = dataBinding !== null ? normalizeHandler(
22824
+ dataBinding?.handler ?? handlerExpr
22825
+ ) : null;
22826
+ const dataForDelegate = dataBinding?.data && (t2.isArrowFunctionExpression(dataBinding.data) || t2.isFunctionExpression(dataBinding.data) ? dataBinding.data : t2.arrowFunctionExpression([], dataBinding.data));
22827
+ const handlerForDelegate = normalizedDataHandler ?? (dataBinding ? normalizeHandler(handlerExpr) : finalHandler);
22828
+ const handlerIsCallableExpr = t2.isArrowFunctionExpression(handlerForDelegate) || t2.isFunctionExpression(handlerForDelegate) || t2.isIdentifier(handlerForDelegate) || t2.isMemberExpression(handlerForDelegate);
22829
+ let handlerToAssign = handlerIsCallableExpr ? handlerForDelegate : t2.arrowFunctionExpression([eventParam], handlerForDelegate);
22830
+ if (dataForDelegate) {
22831
+ let payloadExpr;
22832
+ if (t2.isArrowFunctionExpression(dataForDelegate) && dataForDelegate.params.length === 0) {
22833
+ payloadExpr = t2.isBlockStatement(dataForDelegate.body) ? t2.callExpression(t2.arrowFunctionExpression([], dataForDelegate.body), []) : dataForDelegate.body;
22834
+ } else {
22835
+ payloadExpr = t2.callExpression(dataForDelegate, []);
22836
+ }
22837
+ handlerToAssign = t2.arrowFunctionExpression(
22838
+ [eventParam],
22839
+ t2.callExpression(handlerForDelegate, [payloadExpr])
22840
+ );
22841
+ }
22802
22842
  statements.push(
22803
22843
  t2.expressionStatement(
22804
22844
  t2.assignmentExpression(
22805
22845
  "=",
22806
- t2.memberExpression(targetId, t2.identifier(`$$${eventName}Data`)),
22807
- dataForDelegate
22846
+ t2.memberExpression(targetId, t2.identifier(`$$${eventName}`)),
22847
+ handlerToAssign
22808
22848
  )
22809
22849
  )
22810
22850
  );
22811
- }
22812
- } else {
22813
- ctx.helpersUsed.add("bindEvent");
22814
- ctx.helpersUsed.add("onDestroy");
22815
- const cleanupId = genTemp(ctx, "evt");
22816
- const args = [
22817
- targetId,
22818
- t2.stringLiteral(eventName),
22819
- handlerExpr
22820
- ];
22821
- if (hasEventOptions && binding.eventOptions) {
22822
- const optionProps = [];
22823
- if (binding.eventOptions.capture) {
22824
- optionProps.push(t2.objectProperty(t2.identifier("capture"), t2.booleanLiteral(true)));
22825
- }
22826
- if (binding.eventOptions.passive) {
22827
- optionProps.push(t2.objectProperty(t2.identifier("passive"), t2.booleanLiteral(true)));
22851
+ if (dataForDelegate) {
22852
+ statements.push(
22853
+ t2.expressionStatement(
22854
+ t2.assignmentExpression(
22855
+ "=",
22856
+ t2.memberExpression(targetId, t2.identifier(`$$${eventName}Data`)),
22857
+ dataForDelegate
22858
+ )
22859
+ )
22860
+ );
22828
22861
  }
22829
- if (binding.eventOptions.once) {
22830
- optionProps.push(t2.objectProperty(t2.identifier("once"), t2.booleanLiteral(true)));
22862
+ } else {
22863
+ ctx.helpersUsed.add("bindEvent");
22864
+ ctx.helpersUsed.add("onDestroy");
22865
+ const cleanupId = genTemp(ctx, "evt");
22866
+ const args = [
22867
+ targetId,
22868
+ t2.stringLiteral(eventName),
22869
+ handlerExpr
22870
+ ];
22871
+ if (hasEventOptions && binding.eventOptions) {
22872
+ const optionProps = [];
22873
+ if (binding.eventOptions.capture) {
22874
+ optionProps.push(t2.objectProperty(t2.identifier("capture"), t2.booleanLiteral(true)));
22875
+ }
22876
+ if (binding.eventOptions.passive) {
22877
+ optionProps.push(t2.objectProperty(t2.identifier("passive"), t2.booleanLiteral(true)));
22878
+ }
22879
+ if (binding.eventOptions.once) {
22880
+ optionProps.push(t2.objectProperty(t2.identifier("once"), t2.booleanLiteral(true)));
22881
+ }
22882
+ args.push(t2.objectExpression(optionProps));
22831
22883
  }
22832
- args.push(t2.objectExpression(optionProps));
22833
- }
22834
- statements.push(
22835
- t2.variableDeclaration("const", [
22836
- t2.variableDeclarator(
22837
- cleanupId,
22838
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindEvent), args)
22884
+ statements.push(
22885
+ t2.variableDeclaration("const", [
22886
+ t2.variableDeclarator(
22887
+ cleanupId,
22888
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindEvent), args)
22889
+ )
22890
+ ]),
22891
+ t2.expressionStatement(
22892
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.onDestroy), [cleanupId])
22839
22893
  )
22840
- ]),
22841
- t2.expressionStatement(
22842
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.onDestroy), [cleanupId])
22843
- )
22844
- );
22894
+ );
22895
+ }
22845
22896
  }
22846
22897
  } else if (binding.type === "attr" && binding.name) {
22847
22898
  const attrName = binding.name;
@@ -22903,16 +22954,28 @@ function lowerIntrinsicElement(jsx, ctx) {
22903
22954
  t2.expressionStatement(lowerDomExpression(binding.expr, ctx, containingRegion))
22904
22955
  );
22905
22956
  } else if (binding.type === "text" && binding.expr) {
22906
- ctx.helpersUsed.add("bindText");
22907
22957
  const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion);
22908
- statements.push(
22909
- t2.expressionStatement(
22910
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22911
- targetId,
22912
- t2.arrowFunctionExpression([], valueExpr)
22913
- ])
22914
- )
22915
- );
22958
+ if (isExpressionReactive(binding.expr, ctx)) {
22959
+ ctx.helpersUsed.add("bindText");
22960
+ statements.push(
22961
+ t2.expressionStatement(
22962
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22963
+ targetId,
22964
+ t2.arrowFunctionExpression([], valueExpr)
22965
+ ])
22966
+ )
22967
+ );
22968
+ } else {
22969
+ statements.push(
22970
+ t2.expressionStatement(
22971
+ t2.assignmentExpression(
22972
+ "=",
22973
+ t2.memberExpression(targetId, t2.identifier("data")),
22974
+ t2.callExpression(t2.identifier("String"), [valueExpr])
22975
+ )
22976
+ )
22977
+ );
22978
+ }
22916
22979
  } else if (binding.type === "child" && binding.expr) {
22917
22980
  emitHIRChildBinding(targetId, binding.expr, statements, ctx, containingRegion);
22918
22981
  }
@@ -23216,6 +23279,82 @@ function extractDelegatedEventData(expr, t2) {
23216
23279
  data: dataArg && t2.isExpression(dataArg) ? dataArg : void 0
23217
23280
  };
23218
23281
  }
23282
+ function extractDelegatedEventDataFromHIR(expr, ctx) {
23283
+ if (expr.kind !== "ArrowFunction" && expr.kind !== "FunctionExpression") {
23284
+ return null;
23285
+ }
23286
+ let bodyExpr = null;
23287
+ if (expr.kind === "ArrowFunction") {
23288
+ if (expr.isExpression && !Array.isArray(expr.body)) {
23289
+ bodyExpr = expr.body;
23290
+ }
23291
+ }
23292
+ if (!bodyExpr || bodyExpr.kind !== "CallExpression") {
23293
+ return null;
23294
+ }
23295
+ const callee = bodyExpr.callee;
23296
+ if (callee.kind !== "Identifier") {
23297
+ return null;
23298
+ }
23299
+ if (bodyExpr.arguments.length !== 1) {
23300
+ return null;
23301
+ }
23302
+ if (callee.kind === "Identifier") {
23303
+ const handlerName = deSSAVarName(callee.name);
23304
+ const isTrackedAccessor = ctx.signalVars?.has(handlerName) || ctx.memoVars?.has(handlerName) || ctx.aliasVars?.has(handlerName);
23305
+ if (isTrackedAccessor) {
23306
+ return null;
23307
+ }
23308
+ }
23309
+ const paramNames = new Set(expr.params.map((p) => p.name));
23310
+ const dataExpr = bodyExpr.arguments[0];
23311
+ if (!dataExpr) {
23312
+ return null;
23313
+ }
23314
+ if (hirExpressionUsesIdentifiers(dataExpr, paramNames)) {
23315
+ return null;
23316
+ }
23317
+ return {
23318
+ handler: callee,
23319
+ data: dataExpr
23320
+ };
23321
+ }
23322
+ function hirExpressionUsesIdentifiers(expr, names) {
23323
+ if (expr.kind === "Identifier") {
23324
+ return names.has(deSSAVarName(expr.name));
23325
+ }
23326
+ switch (expr.kind) {
23327
+ case "BinaryExpression":
23328
+ case "LogicalExpression":
23329
+ return hirExpressionUsesIdentifiers(expr.left, names) || hirExpressionUsesIdentifiers(expr.right, names);
23330
+ case "UnaryExpression":
23331
+ return hirExpressionUsesIdentifiers(expr.argument, names);
23332
+ case "ConditionalExpression":
23333
+ return hirExpressionUsesIdentifiers(expr.test, names) || hirExpressionUsesIdentifiers(expr.consequent, names) || hirExpressionUsesIdentifiers(expr.alternate, names);
23334
+ case "CallExpression":
23335
+ case "OptionalCallExpression":
23336
+ return hirExpressionUsesIdentifiers(expr.callee, names) || expr.arguments.some((arg) => hirExpressionUsesIdentifiers(arg, names));
23337
+ case "MemberExpression":
23338
+ case "OptionalMemberExpression":
23339
+ return hirExpressionUsesIdentifiers(expr.object, names) || expr.computed && hirExpressionUsesIdentifiers(expr.property, names);
23340
+ case "ArrayExpression":
23341
+ return expr.elements.some((el) => el && hirExpressionUsesIdentifiers(el, names));
23342
+ case "ObjectExpression":
23343
+ return expr.properties.some((prop) => {
23344
+ if (prop.kind === "SpreadElement") {
23345
+ return hirExpressionUsesIdentifiers(prop.argument, names);
23346
+ }
23347
+ return hirExpressionUsesIdentifiers(prop.key, names) || hirExpressionUsesIdentifiers(prop.value, names);
23348
+ });
23349
+ case "TemplateLiteral":
23350
+ return expr.expressions.some((e) => hirExpressionUsesIdentifiers(e, names));
23351
+ case "ArrowFunction":
23352
+ case "FunctionExpression":
23353
+ return false;
23354
+ default:
23355
+ return false;
23356
+ }
23357
+ }
23219
23358
  function getTrackedCallIdentifier(expr, ctx, itemParamName) {
23220
23359
  if (ctx.t.isCallExpression(expr) && ctx.t.isIdentifier(expr.callee)) {
23221
23360
  if (expr.arguments.length !== 0) return null;
@@ -23226,8 +23365,13 @@ function getTrackedCallIdentifier(expr, ctx, itemParamName) {
23226
23365
  }
23227
23366
  return null;
23228
23367
  }
23229
- function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23368
+ function rewriteSelectorExpression(expr, itemParamName, keyParamName, getSelectorId, ctx) {
23230
23369
  const { t: t2 } = ctx;
23370
+ const usesParamIdentifier = (e) => {
23371
+ if (expressionUsesIdentifier(e, itemParamName, t2)) return true;
23372
+ if (keyParamName && expressionUsesIdentifier(e, keyParamName, t2)) return true;
23373
+ return false;
23374
+ };
23231
23375
  if (t2.isBinaryExpression(expr) && (expr.operator === "===" || expr.operator === "==")) {
23232
23376
  const leftTracked = getTrackedCallIdentifier(
23233
23377
  expr.left,
@@ -23239,7 +23383,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23239
23383
  ctx,
23240
23384
  itemParamName
23241
23385
  );
23242
- if (leftTracked && expressionUsesIdentifier(expr.right, itemParamName, t2)) {
23386
+ if (leftTracked && usesParamIdentifier(expr.right)) {
23243
23387
  return {
23244
23388
  expr: t2.callExpression(getSelectorId(leftTracked), [
23245
23389
  expr.right
@@ -23247,7 +23391,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23247
23391
  changed: true
23248
23392
  };
23249
23393
  }
23250
- if (rightTracked && expressionUsesIdentifier(expr.left, itemParamName, t2)) {
23394
+ if (rightTracked && usesParamIdentifier(expr.left)) {
23251
23395
  return {
23252
23396
  expr: t2.callExpression(getSelectorId(rightTracked), [
23253
23397
  expr.left
@@ -23258,7 +23402,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23258
23402
  }
23259
23403
  let changed = false;
23260
23404
  const rewrite = (node) => {
23261
- const result = rewriteSelectorExpression(node, itemParamName, getSelectorId, ctx);
23405
+ const result = rewriteSelectorExpression(node, itemParamName, keyParamName, getSelectorId, ctx);
23262
23406
  if (result.changed) changed = true;
23263
23407
  return result.expr;
23264
23408
  };
@@ -23319,7 +23463,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23319
23463
  }
23320
23464
  return { expr, changed };
23321
23465
  }
23322
- function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23466
+ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statements, ctx) {
23323
23467
  const { t: t2 } = ctx;
23324
23468
  if (!itemParamName) return;
23325
23469
  if (!t2.isArrowFunctionExpression(callbackExpr) && !t2.isFunctionExpression(callbackExpr)) return;
@@ -23335,7 +23479,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23335
23479
  if (t2.isBlockStatement(fn.body)) {
23336
23480
  for (const stmt of fn.body.body) {
23337
23481
  if (t2.isReturnStatement(stmt) && stmt.argument && t2.isExpression(stmt.argument)) {
23338
- const result = rewriteSelectorExpression(stmt.argument, itemParamName, getSelectorId, ctx);
23482
+ const result = rewriteSelectorExpression(
23483
+ stmt.argument,
23484
+ itemParamName,
23485
+ keyParamName,
23486
+ getSelectorId,
23487
+ ctx
23488
+ );
23339
23489
  if (result.changed) {
23340
23490
  stmt.argument = result.expr;
23341
23491
  }
@@ -23344,7 +23494,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23344
23494
  return;
23345
23495
  }
23346
23496
  if (t2.isExpression(fn.body)) {
23347
- const result = rewriteSelectorExpression(fn.body, itemParamName, getSelectorId, ctx);
23497
+ const result = rewriteSelectorExpression(
23498
+ fn.body,
23499
+ itemParamName,
23500
+ keyParamName,
23501
+ getSelectorId,
23502
+ ctx
23503
+ );
23348
23504
  if (result.changed) {
23349
23505
  fn.body = result.expr;
23350
23506
  }
@@ -23508,7 +23664,14 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23508
23664
  const listId = genTemp(ctx, "list");
23509
23665
  if (isKeyed) {
23510
23666
  const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : null : null;
23511
- applySelectorHoist(callbackExpr, itemParamName, statements, ctx);
23667
+ const keyParamName = ctx.listKeyParamName ?? null;
23668
+ applySelectorHoist(
23669
+ callbackExpr,
23670
+ itemParamName,
23671
+ keyParamName,
23672
+ statements,
23673
+ ctx
23674
+ );
23512
23675
  }
23513
23676
  if (isKeyed && keyExpr) {
23514
23677
  let keyExprAst = lowerExpression(keyExpr, ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fictjs/compiler",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Babel plugin for Fict Compiler",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -45,7 +45,7 @@
45
45
  "@types/babel__helper-plugin-utils": "^7.10.3",
46
46
  "@types/babel__traverse": "^7.28.0",
47
47
  "tsup": "^8.5.1",
48
- "@fictjs/runtime": "0.0.9"
48
+ "@fictjs/runtime": "0.0.11"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "tsup src/index.ts --format cjs,esm --dts",