@fictjs/compiler 0.0.8 → 0.0.10

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 +522 -230
  2. package/dist/index.js +522 -230
  3. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -14372,6 +14372,9 @@ function pathToString(path) {
14372
14372
 
14373
14373
  // src/ir/build-hir.ts
14374
14374
  var destructuringTempCounter = 0;
14375
+ var getLoc = (node) => {
14376
+ return node?.loc ?? null;
14377
+ };
14375
14378
  function normalizeVarKind(kind) {
14376
14379
  return kind === "const" || kind === "let" || kind === "var" ? kind : "let";
14377
14380
  }
@@ -14441,7 +14444,8 @@ function buildHIR(ast) {
14441
14444
  functions.push(
14442
14445
  convertFunction(name, stmt.params, stmt.body.body, {
14443
14446
  noMemo: programNoMemo,
14444
- directives: stmt.body.directives
14447
+ directives: stmt.body.directives,
14448
+ loc: getLoc(stmt)
14445
14449
  })
14446
14450
  );
14447
14451
  continue;
@@ -14454,7 +14458,8 @@ function buildHIR(ast) {
14454
14458
  functions.push(
14455
14459
  convertFunction(name, decl.params, decl.body.body, {
14456
14460
  noMemo: programNoMemo,
14457
- directives: decl.body.directives
14461
+ directives: decl.body.directives,
14462
+ loc: getLoc(decl)
14458
14463
  })
14459
14464
  );
14460
14465
  postamble.push({ kind: "ExportFunction", name });
@@ -14472,9 +14477,11 @@ function buildHIR(ast) {
14472
14477
  const hasExpressionBody = isArrow && !t.isBlockStatement(body);
14473
14478
  const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
14474
14479
  noMemo: programNoMemo,
14475
- directives: body.directives
14480
+ directives: body.directives,
14481
+ loc: getLoc(v.init ?? v)
14476
14482
  }) : convertFunction(name, params, [t.returnStatement(body)], {
14477
- noMemo: programNoMemo
14483
+ noMemo: programNoMemo,
14484
+ loc: getLoc(v.init ?? v)
14478
14485
  });
14479
14486
  fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
14480
14487
  functions.push(fnHIR);
@@ -14499,7 +14506,8 @@ function buildHIR(ast) {
14499
14506
  functions.push(
14500
14507
  convertFunction(name, decl.params, decl.body.body, {
14501
14508
  noMemo: programNoMemo,
14502
- directives: decl.body.directives
14509
+ directives: decl.body.directives,
14510
+ loc: getLoc(decl)
14503
14511
  })
14504
14512
  );
14505
14513
  postamble.push({ kind: "ExportDefault", name });
@@ -14524,13 +14532,15 @@ function buildHIR(ast) {
14524
14532
  const hasExpressionBody = isArrow && !t.isBlockStatement(body);
14525
14533
  const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
14526
14534
  noMemo: programNoMemo,
14527
- directives: body.directives
14535
+ directives: body.directives,
14536
+ loc: getLoc(decl.init ?? decl)
14528
14537
  }) : convertFunction(
14529
14538
  name,
14530
14539
  params,
14531
14540
  [t.returnStatement(body)],
14532
14541
  {
14533
- noMemo: programNoMemo
14542
+ noMemo: programNoMemo,
14543
+ loc: getLoc(decl.init ?? decl)
14534
14544
  }
14535
14545
  );
14536
14546
  fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
@@ -15038,11 +15048,12 @@ function convertFunction(name, params, body, options) {
15038
15048
  name,
15039
15049
  params: paramIds,
15040
15050
  blocks,
15041
- meta: hasNoMemo ? { noMemo: true } : void 0
15051
+ meta: hasNoMemo ? { noMemo: true } : void 0,
15052
+ loc: options?.loc ?? null
15042
15053
  };
15043
15054
  }
15044
15055
  function convertStatementsToHIRFunction(name, statements) {
15045
- return convertFunction(name, [], statements);
15056
+ return convertFunction(name, [], statements, { loc: getLoc(statements[0]) });
15046
15057
  }
15047
15058
  function convertAssignmentValue(expr) {
15048
15059
  const right = convertExpression(expr.right);
@@ -15540,14 +15551,16 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
15540
15551
  return bb;
15541
15552
  }
15542
15553
  function convertExpression(node) {
15543
- if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name };
15554
+ const loc = getLoc(node);
15555
+ if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name, loc };
15544
15556
  if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node))
15545
- return { kind: "Literal", value: node.value ?? null };
15557
+ return { kind: "Literal", value: node.value ?? null, loc };
15546
15558
  if (t.isCallExpression(node)) {
15547
15559
  const call = {
15548
15560
  kind: "CallExpression",
15549
15561
  callee: convertExpression(node.callee),
15550
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
15562
+ arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15563
+ loc
15551
15564
  };
15552
15565
  return call;
15553
15566
  }
@@ -15562,7 +15575,8 @@ function convertExpression(node) {
15562
15575
  object,
15563
15576
  property,
15564
15577
  computed: node.computed,
15565
- optional: node.optional ?? true
15578
+ optional: node.optional ?? true,
15579
+ loc
15566
15580
  };
15567
15581
  return optionalMember;
15568
15582
  }
@@ -15571,7 +15585,8 @@ function convertExpression(node) {
15571
15585
  object,
15572
15586
  property,
15573
15587
  computed: node.computed,
15574
- optional: false
15588
+ optional: false,
15589
+ loc
15575
15590
  };
15576
15591
  return member;
15577
15592
  }
@@ -15580,7 +15595,8 @@ function convertExpression(node) {
15580
15595
  kind: "BinaryExpression",
15581
15596
  operator: node.operator,
15582
15597
  left: convertExpression(node.left),
15583
- right: convertExpression(node.right)
15598
+ right: convertExpression(node.right),
15599
+ loc
15584
15600
  };
15585
15601
  return bin;
15586
15602
  }
@@ -15589,7 +15605,8 @@ function convertExpression(node) {
15589
15605
  kind: "UnaryExpression",
15590
15606
  operator: node.operator,
15591
15607
  argument: convertExpression(node.argument),
15592
- prefix: node.prefix
15608
+ prefix: node.prefix,
15609
+ loc
15593
15610
  };
15594
15611
  return un;
15595
15612
  }
@@ -15598,7 +15615,8 @@ function convertExpression(node) {
15598
15615
  kind: "LogicalExpression",
15599
15616
  operator: node.operator,
15600
15617
  left: convertExpression(node.left),
15601
- right: convertExpression(node.right)
15618
+ right: convertExpression(node.right),
15619
+ loc
15602
15620
  };
15603
15621
  return log;
15604
15622
  }
@@ -15607,7 +15625,8 @@ function convertExpression(node) {
15607
15625
  kind: "ConditionalExpression",
15608
15626
  test: convertExpression(node.test),
15609
15627
  consequent: convertExpression(node.consequent),
15610
- alternate: convertExpression(node.alternate)
15628
+ alternate: convertExpression(node.alternate),
15629
+ loc
15611
15630
  };
15612
15631
  return cond;
15613
15632
  }
@@ -15619,12 +15638,14 @@ function convertExpression(node) {
15619
15638
  if (t.isSpreadElement(el)) {
15620
15639
  return {
15621
15640
  kind: "SpreadElement",
15622
- argument: convertExpression(el.argument)
15641
+ argument: convertExpression(el.argument),
15642
+ loc: getLoc(el)
15623
15643
  };
15624
15644
  }
15625
15645
  if (t.isExpression(el)) return convertExpression(el);
15626
15646
  return void 0;
15627
- }).filter(Boolean)
15647
+ }).filter(Boolean),
15648
+ loc
15628
15649
  };
15629
15650
  return arr;
15630
15651
  }
@@ -15635,7 +15656,8 @@ function convertExpression(node) {
15635
15656
  if (t.isSpreadElement(prop)) {
15636
15657
  return {
15637
15658
  kind: "SpreadElement",
15638
- argument: convertExpression(prop.argument)
15659
+ argument: convertExpression(prop.argument),
15660
+ loc: getLoc(prop)
15639
15661
  };
15640
15662
  }
15641
15663
  if (t.isObjectMethod(prop)) {
@@ -15652,7 +15674,8 @@ function convertExpression(node) {
15652
15674
  return {
15653
15675
  kind: "Property",
15654
15676
  key: keyExpr2,
15655
- value: convertExpression(fnExpr)
15677
+ value: convertExpression(fnExpr),
15678
+ loc: getLoc(prop)
15656
15679
  };
15657
15680
  }
15658
15681
  if (!t.isObjectProperty(prop) || prop.computed) return void 0;
@@ -15662,9 +15685,12 @@ function convertExpression(node) {
15662
15685
  return {
15663
15686
  kind: "Property",
15664
15687
  key: keyExpr,
15665
- value: convertExpression(prop.value)
15688
+ value: convertExpression(prop.value),
15689
+ shorthand: prop.shorthand && t.isIdentifier(prop.value),
15690
+ loc: getLoc(prop)
15666
15691
  };
15667
- }).filter(Boolean)
15692
+ }).filter(Boolean),
15693
+ loc
15668
15694
  };
15669
15695
  return obj;
15670
15696
  }
@@ -15677,38 +15703,42 @@ function convertExpression(node) {
15677
15703
  if (t.isJSXText(child)) {
15678
15704
  const text = child.value;
15679
15705
  if (text.trim()) {
15680
- children.push({ kind: "text", value: text });
15706
+ children.push({ kind: "text", value: text, loc: getLoc(child) });
15681
15707
  }
15682
15708
  } else if (t.isJSXExpressionContainer(child)) {
15683
15709
  if (!t.isJSXEmptyExpression(child.expression)) {
15684
15710
  children.push({
15685
15711
  kind: "expression",
15686
- value: convertExpression(child.expression)
15712
+ value: convertExpression(child.expression),
15713
+ loc: getLoc(child)
15687
15714
  });
15688
15715
  }
15689
15716
  } else if (t.isJSXElement(child)) {
15690
15717
  children.push({
15691
15718
  kind: "element",
15692
- value: convertJSXElement(child)
15719
+ value: convertJSXElement(child),
15720
+ loc: getLoc(child)
15693
15721
  });
15694
15722
  } else if (t.isJSXFragment(child)) {
15695
15723
  for (const fragChild of child.children) {
15696
15724
  if (t.isJSXText(fragChild)) {
15697
15725
  const text = fragChild.value;
15698
15726
  if (text.trim()) {
15699
- children.push({ kind: "text", value: text });
15727
+ children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
15700
15728
  }
15701
15729
  } else if (t.isJSXExpressionContainer(fragChild)) {
15702
15730
  if (!t.isJSXEmptyExpression(fragChild.expression)) {
15703
15731
  children.push({
15704
15732
  kind: "expression",
15705
- value: convertExpression(fragChild.expression)
15733
+ value: convertExpression(fragChild.expression),
15734
+ loc: getLoc(fragChild)
15706
15735
  });
15707
15736
  }
15708
15737
  } else if (t.isJSXElement(fragChild)) {
15709
15738
  children.push({
15710
15739
  kind: "element",
15711
- value: convertJSXElement(fragChild)
15740
+ value: convertJSXElement(fragChild),
15741
+ loc: getLoc(fragChild)
15712
15742
  });
15713
15743
  }
15714
15744
  }
@@ -15716,24 +15746,27 @@ function convertExpression(node) {
15716
15746
  }
15717
15747
  return {
15718
15748
  kind: "JSXElement",
15719
- tagName: { kind: "Identifier", name: "Fragment" },
15749
+ tagName: { kind: "Identifier", name: "Fragment", loc: getLoc(node) },
15720
15750
  isComponent: true,
15721
15751
  attributes: [],
15722
- children
15752
+ children,
15753
+ loc: getLoc(node)
15723
15754
  };
15724
15755
  }
15725
15756
  if (t.isArrowFunctionExpression(node)) {
15726
15757
  if (t.isBlockStatement(node.body)) {
15727
15758
  const nested = convertFunction(void 0, node.params, node.body.body, {
15728
15759
  noMemo: hasNoMemoDirectiveInStatements(node.body.body),
15729
- directives: node.body.directives
15760
+ directives: node.body.directives,
15761
+ loc: getLoc(node)
15730
15762
  });
15731
15763
  const arrow = {
15732
15764
  kind: "ArrowFunction",
15733
15765
  params: nested.params,
15734
15766
  body: nested.blocks,
15735
15767
  isExpression: false,
15736
- isAsync: node.async
15768
+ isAsync: node.async,
15769
+ loc
15737
15770
  };
15738
15771
  return arrow;
15739
15772
  } else {
@@ -15744,7 +15777,8 @@ function convertExpression(node) {
15744
15777
  ).flat(),
15745
15778
  body: convertExpression(node.body),
15746
15779
  isExpression: true,
15747
- isAsync: node.async
15780
+ isAsync: node.async,
15781
+ loc
15748
15782
  };
15749
15783
  return arrow;
15750
15784
  }
@@ -15752,14 +15786,16 @@ function convertExpression(node) {
15752
15786
  if (t.isFunctionExpression(node)) {
15753
15787
  const nested = convertFunction(void 0, node.params, node.body.body, {
15754
15788
  noMemo: hasNoMemoDirectiveInStatements(node.body.body),
15755
- directives: node.body.directives
15789
+ directives: node.body.directives,
15790
+ loc: getLoc(node)
15756
15791
  });
15757
15792
  const fn = {
15758
15793
  kind: "FunctionExpression",
15759
15794
  name: node.id?.name ?? "",
15760
15795
  params: nested.params,
15761
15796
  body: nested.blocks,
15762
- isAsync: node.async
15797
+ isAsync: node.async,
15798
+ loc
15763
15799
  };
15764
15800
  return fn;
15765
15801
  }
@@ -15768,7 +15804,8 @@ function convertExpression(node) {
15768
15804
  kind: "AssignmentExpression",
15769
15805
  operator: node.operator,
15770
15806
  left: convertExpression(node.left),
15771
- right: convertExpression(node.right)
15807
+ right: convertExpression(node.right),
15808
+ loc
15772
15809
  };
15773
15810
  return assign;
15774
15811
  }
@@ -15777,7 +15814,8 @@ function convertExpression(node) {
15777
15814
  kind: "UpdateExpression",
15778
15815
  operator: node.operator,
15779
15816
  argument: convertExpression(node.argument),
15780
- prefix: node.prefix
15817
+ prefix: node.prefix,
15818
+ loc
15781
15819
  };
15782
15820
  return update;
15783
15821
  }
@@ -15785,34 +15823,39 @@ function convertExpression(node) {
15785
15823
  const template = {
15786
15824
  kind: "TemplateLiteral",
15787
15825
  quasis: node.quasis.map((q) => q.value.cooked ?? q.value.raw),
15788
- expressions: node.expressions.map((e) => convertExpression(e))
15826
+ expressions: node.expressions.map((e) => convertExpression(e)),
15827
+ loc
15789
15828
  };
15790
15829
  return template;
15791
15830
  }
15792
15831
  if (t.isAwaitExpression(node)) {
15793
15832
  return {
15794
15833
  kind: "AwaitExpression",
15795
- argument: convertExpression(node.argument)
15834
+ argument: convertExpression(node.argument),
15835
+ loc
15796
15836
  };
15797
15837
  }
15798
15838
  if (t.isNewExpression(node)) {
15799
15839
  return {
15800
15840
  kind: "NewExpression",
15801
15841
  callee: convertExpression(node.callee),
15802
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
15842
+ arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15843
+ loc
15803
15844
  };
15804
15845
  }
15805
15846
  if (t.isSequenceExpression(node)) {
15806
15847
  return {
15807
15848
  kind: "SequenceExpression",
15808
- expressions: node.expressions.map((e) => convertExpression(e))
15849
+ expressions: node.expressions.map((e) => convertExpression(e)),
15850
+ loc
15809
15851
  };
15810
15852
  }
15811
15853
  if (t.isYieldExpression(node)) {
15812
15854
  return {
15813
15855
  kind: "YieldExpression",
15814
15856
  argument: node.argument ? convertExpression(node.argument) : null,
15815
- delegate: node.delegate
15857
+ delegate: node.delegate,
15858
+ loc
15816
15859
  };
15817
15860
  }
15818
15861
  if (t.isOptionalCallExpression(node)) {
@@ -15820,7 +15863,8 @@ function convertExpression(node) {
15820
15863
  kind: "OptionalCallExpression",
15821
15864
  callee: convertExpression(node.callee),
15822
15865
  arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15823
- optional: node.optional
15866
+ optional: node.optional,
15867
+ loc
15824
15868
  };
15825
15869
  }
15826
15870
  if (t.isTaggedTemplateExpression(node)) {
@@ -15832,8 +15876,10 @@ function convertExpression(node) {
15832
15876
  quasis: node.quasi.quasis.map((q) => q.value.cooked ?? q.value.raw),
15833
15877
  expressions: node.quasi.expressions.map(
15834
15878
  (e) => convertExpression(e)
15835
- )
15836
- }
15879
+ ),
15880
+ loc: getLoc(node.quasi)
15881
+ },
15882
+ loc
15837
15883
  };
15838
15884
  }
15839
15885
  if (t.isClassExpression(node)) {
@@ -15841,17 +15887,18 @@ function convertExpression(node) {
15841
15887
  kind: "ClassExpression",
15842
15888
  name: node.id?.name,
15843
15889
  superClass: node.superClass ? convertExpression(node.superClass) : void 0,
15844
- body: node.body.body
15890
+ body: node.body.body,
15845
15891
  // Store as Babel AST for now
15892
+ loc
15846
15893
  };
15847
15894
  }
15848
15895
  if (t.isThisExpression(node)) {
15849
- return { kind: "ThisExpression" };
15896
+ return { kind: "ThisExpression", loc };
15850
15897
  }
15851
15898
  if (t.isSuper(node)) {
15852
- return { kind: "SuperExpression" };
15899
+ return { kind: "SuperExpression", loc };
15853
15900
  }
15854
- const fallback = { kind: "Literal", value: void 0 };
15901
+ const fallback = { kind: "Literal", value: void 0, loc };
15855
15902
  return fallback;
15856
15903
  }
15857
15904
  function convertJSXElement(node) {
@@ -15862,7 +15909,7 @@ function convertJSXElement(node) {
15862
15909
  const name = opening.name.name;
15863
15910
  const firstChar = name[0];
15864
15911
  if (firstChar && firstChar === firstChar.toUpperCase()) {
15865
- tagName = { kind: "Identifier", name };
15912
+ tagName = { kind: "Identifier", name, loc: getLoc(opening.name) };
15866
15913
  isComponent = true;
15867
15914
  } else {
15868
15915
  tagName = name;
@@ -15880,20 +15927,22 @@ function convertJSXElement(node) {
15880
15927
  name: "",
15881
15928
  value: null,
15882
15929
  isSpread: true,
15883
- spreadExpr: convertExpression(attr.argument)
15930
+ spreadExpr: convertExpression(attr.argument),
15931
+ loc: getLoc(attr)
15884
15932
  });
15885
15933
  } else if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
15886
15934
  let value = null;
15887
15935
  if (attr.value) {
15888
15936
  if (t.isStringLiteral(attr.value)) {
15889
- value = { kind: "Literal", value: attr.value.value };
15937
+ value = { kind: "Literal", value: attr.value.value, loc: getLoc(attr.value) };
15890
15938
  } else if (t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
15891
15939
  value = convertExpression(attr.value.expression);
15892
15940
  }
15893
15941
  }
15894
15942
  attributes.push({
15895
15943
  name: attr.name.name,
15896
- value
15944
+ value,
15945
+ loc: getLoc(attr)
15897
15946
  });
15898
15947
  }
15899
15948
  }
@@ -15902,38 +15951,42 @@ function convertJSXElement(node) {
15902
15951
  if (t.isJSXText(child)) {
15903
15952
  const text = child.value;
15904
15953
  if (text.trim()) {
15905
- children.push({ kind: "text", value: text });
15954
+ children.push({ kind: "text", value: text, loc: getLoc(child) });
15906
15955
  }
15907
15956
  } else if (t.isJSXExpressionContainer(child)) {
15908
15957
  if (!t.isJSXEmptyExpression(child.expression)) {
15909
15958
  children.push({
15910
15959
  kind: "expression",
15911
- value: convertExpression(child.expression)
15960
+ value: convertExpression(child.expression),
15961
+ loc: getLoc(child)
15912
15962
  });
15913
15963
  }
15914
15964
  } else if (t.isJSXElement(child)) {
15915
15965
  children.push({
15916
15966
  kind: "element",
15917
- value: convertJSXElement(child)
15967
+ value: convertJSXElement(child),
15968
+ loc: getLoc(child)
15918
15969
  });
15919
15970
  } else if (t.isJSXFragment(child)) {
15920
15971
  for (const fragChild of child.children) {
15921
15972
  if (t.isJSXText(fragChild)) {
15922
15973
  const text = fragChild.value;
15923
15974
  if (text.trim()) {
15924
- children.push({ kind: "text", value: text });
15975
+ children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
15925
15976
  }
15926
15977
  } else if (t.isJSXExpressionContainer(fragChild)) {
15927
15978
  if (!t.isJSXEmptyExpression(fragChild.expression)) {
15928
15979
  children.push({
15929
15980
  kind: "expression",
15930
- value: convertExpression(fragChild.expression)
15981
+ value: convertExpression(fragChild.expression),
15982
+ loc: getLoc(fragChild)
15931
15983
  });
15932
15984
  }
15933
15985
  } else if (t.isJSXElement(fragChild)) {
15934
15986
  children.push({
15935
15987
  kind: "element",
15936
- value: convertJSXElement(fragChild)
15988
+ value: convertJSXElement(fragChild),
15989
+ loc: getLoc(fragChild)
15937
15990
  });
15938
15991
  }
15939
15992
  }
@@ -15944,21 +15997,27 @@ function convertJSXElement(node) {
15944
15997
  tagName,
15945
15998
  isComponent,
15946
15999
  attributes,
15947
- children
16000
+ children,
16001
+ loc: getLoc(node)
15948
16002
  };
15949
16003
  }
15950
16004
  function convertJSXMemberExpr(node) {
15951
16005
  let object;
15952
16006
  if (t.isJSXIdentifier(node.object)) {
15953
- object = { kind: "Identifier", name: node.object.name };
16007
+ object = { kind: "Identifier", name: node.object.name, loc: getLoc(node.object) };
15954
16008
  } else {
15955
16009
  object = convertJSXMemberExpr(node.object);
15956
16010
  }
15957
16011
  return {
15958
16012
  kind: "MemberExpression",
15959
16013
  object,
15960
- property: { kind: "Identifier", name: node.property.name },
15961
- computed: false
16014
+ property: {
16015
+ kind: "Identifier",
16016
+ name: node.property.name,
16017
+ loc: getLoc(node.property)
16018
+ },
16019
+ computed: false,
16020
+ loc: getLoc(node)
15962
16021
  };
15963
16022
  }
15964
16023
 
@@ -18272,7 +18331,8 @@ function lowerNodeWithRegionContext(node, t2, ctx, declaredVars, regionCtx) {
18272
18331
  t2.blockStatement(conseqStmts),
18273
18332
  altStmts ? t2.blockStatement(altStmts) : null
18274
18333
  );
18275
- 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);
18276
18336
  if (shouldWrapEffect) {
18277
18337
  ctx.helpersUsed.add("useEffect");
18278
18338
  ctx.needsCtx = true;
@@ -18500,31 +18560,53 @@ function lowerStructuredNodeForRegion(node, region, t2, ctx, declaredVars, regio
18500
18560
  return stmt ? [stmt] : [];
18501
18561
  }
18502
18562
  case "if": {
18503
- const consequent = lowerStructuredNodeForRegion(
18504
- node.consequent,
18505
- region,
18506
- t2,
18507
- ctx,
18508
- declaredVars,
18509
- regionCtx,
18510
- skipInstructions
18511
- );
18512
- const alternate = node.alternate ? lowerStructuredNodeForRegion(
18513
- node.alternate,
18514
- region,
18515
- t2,
18516
- ctx,
18517
- declaredVars,
18518
- regionCtx,
18519
- skipInstructions
18520
- ) : [];
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) : [];
18521
18596
  if (consequent.length === 0 && alternate.length === 0) return [];
18522
- const ifStmt = t2.ifStatement(
18597
+ const buildIfStmt = (cons, alt) => t2.ifStatement(
18523
18598
  lowerExpressionWithDeSSA(node.test, ctx),
18524
- t2.blockStatement(consequent),
18525
- alternate.length > 0 ? t2.blockStatement(alternate) : null
18599
+ t2.blockStatement(cons),
18600
+ alt.length > 0 ? t2.blockStatement(alt) : null
18526
18601
  );
18527
- 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
+ }
18528
18610
  if (shouldWrapEffect) {
18529
18611
  ctx.helpersUsed.add("useEffect");
18530
18612
  ctx.needsCtx = true;
@@ -18916,11 +18998,17 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
18916
18998
  if (uniqueOutputNames.length === 0) {
18917
18999
  ctx.helpersUsed.add("useEffect");
18918
19000
  ctx.needsCtx = true;
18919
- const effectCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
19001
+ const effectCallArgs = [
18920
19002
  t2.identifier("__fictCtx"),
18921
- t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements)),
18922
- t2.numericLiteral(reserveHookSlot(ctx))
18923
- ]);
19003
+ t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements))
19004
+ ];
19005
+ {
19006
+ const slot = reserveHookSlot(ctx);
19007
+ if (slot >= 0) {
19008
+ effectCallArgs.push(t2.numericLiteral(slot));
19009
+ }
19010
+ }
19011
+ const effectCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), effectCallArgs);
18924
19012
  statements.push(t2.expressionStatement(effectCall));
18925
19013
  } else {
18926
19014
  ctx.helpersUsed.add("useMemo");
@@ -18953,11 +19041,15 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
18953
19041
  };
18954
19042
  const returnObj = t2.objectExpression(uniqueOutputNames.map((name) => buildOutputProperty(name)));
18955
19043
  const memoBody = t2.blockStatement([...bodyStatements, t2.returnStatement(returnObj)]);
18956
- const memoCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), [
19044
+ const slot = reserveHookSlot(ctx);
19045
+ const memoArgs = [
18957
19046
  t2.identifier("__fictCtx"),
18958
- t2.arrowFunctionExpression([], memoBody),
18959
- t2.numericLiteral(reserveHookSlot(ctx))
18960
- ]);
19047
+ t2.arrowFunctionExpression([], memoBody)
19048
+ ];
19049
+ if (slot >= 0) {
19050
+ memoArgs.push(t2.numericLiteral(slot));
19051
+ }
19052
+ const memoCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs);
18961
19053
  const regionVarName = `__region_${region.id}`;
18962
19054
  statements.push(
18963
19055
  t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
@@ -19014,7 +19106,10 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
19014
19106
  t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
19015
19107
  t2.identifier("__fictCtx"),
19016
19108
  t2.arrowFunctionExpression([], effectBody),
19017
- t2.numericLiteral(reserveHookSlot(ctx))
19109
+ (() => {
19110
+ const slot2 = reserveHookSlot(ctx);
19111
+ return slot2 >= 0 ? t2.numericLiteral(slot2) : t2.identifier("undefined");
19112
+ })()
19018
19113
  ])
19019
19114
  )
19020
19115
  );
@@ -19232,11 +19327,15 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
19232
19327
  ctx.helpersUsed.add("useMemo");
19233
19328
  ctx.needsCtx = true;
19234
19329
  const regionVarName = `__region_${region.id}`;
19235
- const memoCall = t2.callExpression(t2.identifier("__fictUseMemo"), [
19330
+ const slotForMemo = reserveHookSlot(ctx);
19331
+ const memoArgs = [
19236
19332
  t2.identifier("__fictCtx"),
19237
- t2.arrowFunctionExpression([], t2.blockStatement(memoBody)),
19238
- t2.numericLiteral(reserveHookSlot(ctx))
19239
- ]);
19333
+ t2.arrowFunctionExpression([], t2.blockStatement(memoBody))
19334
+ ];
19335
+ if (slotForMemo >= 0) {
19336
+ memoArgs.push(t2.numericLiteral(slotForMemo));
19337
+ }
19338
+ const memoCall = t2.callExpression(t2.identifier("__fictUseMemo"), memoArgs);
19240
19339
  statements.push(
19241
19340
  t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
19242
19341
  );
@@ -19258,6 +19357,9 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
19258
19357
  return statements;
19259
19358
  }
19260
19359
  function reserveHookSlot(ctx) {
19360
+ if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
19361
+ return -1;
19362
+ }
19261
19363
  const slot = ctx.nextHookSlot ?? 0;
19262
19364
  ctx.nextHookSlot = slot + 1;
19263
19365
  return slot;
@@ -19328,7 +19430,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19328
19430
  t2.arrowFunctionExpression([], expr)
19329
19431
  ];
19330
19432
  if (inRegionMemo) {
19331
- args.push(t2.numericLiteral(reserveHookSlot(ctx)));
19433
+ const slot = reserveHookSlot(ctx);
19434
+ if (slot >= 0) {
19435
+ args.push(t2.numericLiteral(slot));
19436
+ }
19332
19437
  }
19333
19438
  ctx.helpersUsed.add("useMemo");
19334
19439
  ctx.needsCtx = true;
@@ -19528,7 +19633,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19528
19633
  (dep) => ctx.trackedVars.has(deSSAVarName(dep))
19529
19634
  );
19530
19635
  const usesTracked = expressionUsesTracked(instr.value, ctx);
19531
- const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && (usesTracked || hasTrackedControlDep);
19636
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
19637
+ const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && !inNonReactiveScope && (usesTracked || hasTrackedControlDep);
19532
19638
  if (shouldWrapExpr) {
19533
19639
  ctx.helpersUsed.add("useEffect");
19534
19640
  ctx.needsCtx = true;
@@ -19843,6 +19949,17 @@ function deSSAJSXChild(child, t2) {
19843
19949
  // src/ir/codegen.ts
19844
19950
  var HOOK_SLOT_BASE = 1e3;
19845
19951
  var HOOK_NAME_PREFIX = "use";
19952
+ var cloneLoc = (loc) => loc === void 0 ? void 0 : loc === null ? null : {
19953
+ start: { ...loc.start },
19954
+ end: { ...loc.end },
19955
+ filename: loc.filename,
19956
+ identifierName: loc.identifierName
19957
+ };
19958
+ function setNodeLoc(node, loc) {
19959
+ if (loc === void 0) return node;
19960
+ node.loc = cloneLoc(loc) ?? null;
19961
+ return node;
19962
+ }
19846
19963
  function isHookName(name) {
19847
19964
  return !!name && name.startsWith(HOOK_NAME_PREFIX);
19848
19965
  }
@@ -19876,13 +19993,22 @@ function applyRegionToContext(ctx, region) {
19876
19993
  return prevRegion;
19877
19994
  }
19878
19995
  function reserveHookSlot2(ctx) {
19996
+ if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
19997
+ return -1;
19998
+ }
19879
19999
  const slot = ctx.nextHookSlot ?? HOOK_SLOT_BASE;
19880
20000
  ctx.nextHookSlot = slot + 1;
19881
20001
  return slot;
19882
20002
  }
19883
20003
  function expressionContainsJSX(expr) {
20004
+ if (Array.isArray(expr)) {
20005
+ return expr.some((item) => expressionContainsJSX(item));
20006
+ }
19884
20007
  if (!expr || typeof expr !== "object") return false;
19885
20008
  if (expr.kind === "JSXElement") return true;
20009
+ if (Array.isArray(expr.instructions)) {
20010
+ return expr.instructions.some((i) => expressionContainsJSX(i?.value ?? i));
20011
+ }
19886
20012
  switch (expr.kind) {
19887
20013
  case "CallExpression":
19888
20014
  if (expressionContainsJSX(expr.callee)) return true;
@@ -19895,10 +20021,29 @@ function expressionContainsJSX(expr) {
19895
20021
  return expressionContainsJSX(expr.test) || expressionContainsJSX(expr.consequent) || expressionContainsJSX(expr.alternate);
19896
20022
  case "ArrowFunction":
19897
20023
  return expressionContainsJSX(expr.body);
20024
+ case "FunctionExpression":
20025
+ if (Array.isArray(expr.body)) {
20026
+ return expr.body.some(
20027
+ (block) => block.instructions?.some((i) => expressionContainsJSX(i.value))
20028
+ );
20029
+ }
20030
+ return false;
19898
20031
  default:
19899
20032
  return false;
19900
20033
  }
19901
20034
  }
20035
+ function withNoMemoAndDynamicHooks(ctx, fn) {
20036
+ const prevNoMemo = ctx.noMemo;
20037
+ const prevDynamic = ctx.dynamicHookSlotDepth ?? 0;
20038
+ ctx.noMemo = true;
20039
+ ctx.dynamicHookSlotDepth = prevDynamic + 1;
20040
+ try {
20041
+ return fn();
20042
+ } finally {
20043
+ ctx.noMemo = prevNoMemo;
20044
+ ctx.dynamicHookSlotDepth = prevDynamic;
20045
+ }
20046
+ }
19902
20047
  function functionContainsJSX(fn) {
19903
20048
  for (const block of fn.blocks) {
19904
20049
  for (const instr of block.instructions) {
@@ -20997,18 +21142,25 @@ function lowerTrackedExpression(expr, ctx) {
20997
21142
  }
20998
21143
  function lowerInstruction(instr, ctx) {
20999
21144
  const { t: t2 } = ctx;
21145
+ const applyLoc = (stmt) => {
21146
+ if (!stmt) return stmt;
21147
+ const baseLoc = instr.loc ?? (instr.kind === "Assign" || instr.kind === "Expression" ? instr.value.loc : void 0);
21148
+ return setNodeLoc(stmt, baseLoc);
21149
+ };
21000
21150
  if (instr.kind === "Assign") {
21001
21151
  const baseName2 = deSSAVarName(instr.target.name);
21002
21152
  const isFunctionDecl = instr.value.kind === "FunctionExpression" && (instr.declarationKind === "function" || !instr.declarationKind && instr.value.name === baseName2);
21003
21153
  if (isFunctionDecl) {
21004
21154
  const loweredFn = lowerExpression(instr.value, ctx);
21005
21155
  if (t2.isFunctionExpression(loweredFn)) {
21006
- return t2.functionDeclaration(
21007
- t2.identifier(baseName2),
21008
- loweredFn.params,
21009
- loweredFn.body,
21010
- loweredFn.generator ?? false,
21011
- loweredFn.async ?? false
21156
+ return applyLoc(
21157
+ t2.functionDeclaration(
21158
+ t2.identifier(baseName2),
21159
+ loweredFn.params,
21160
+ loweredFn.body,
21161
+ loweredFn.generator ?? false,
21162
+ loweredFn.async ?? false
21163
+ )
21012
21164
  );
21013
21165
  }
21014
21166
  }
@@ -21023,12 +21175,16 @@ function lowerInstruction(instr, ctx) {
21023
21175
  ctx.memoVars?.add(baseName2);
21024
21176
  }
21025
21177
  if (declKind) {
21026
- return t2.variableDeclaration(declKind, [
21027
- t2.variableDeclarator(t2.identifier(baseName2), hookMember.member)
21028
- ]);
21178
+ return applyLoc(
21179
+ t2.variableDeclaration(declKind, [
21180
+ t2.variableDeclarator(t2.identifier(baseName2), hookMember.member)
21181
+ ])
21182
+ );
21029
21183
  }
21030
- return t2.expressionStatement(
21031
- t2.assignmentExpression("=", t2.identifier(baseName2), hookMember.member)
21184
+ return applyLoc(
21185
+ t2.expressionStatement(
21186
+ t2.assignmentExpression("=", t2.identifier(baseName2), hookMember.member)
21187
+ )
21032
21188
  );
21033
21189
  }
21034
21190
  if (instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && isHookName(instr.value.callee.name)) {
@@ -21042,16 +21198,24 @@ function lowerInstruction(instr, ctx) {
21042
21198
  }
21043
21199
  }
21044
21200
  if (ctx.signalVars?.has(baseName2)) {
21045
- return t2.expressionStatement(
21046
- t2.callExpression(t2.identifier(baseName2), [lowerTrackedExpression(instr.value, ctx)])
21201
+ return applyLoc(
21202
+ t2.expressionStatement(
21203
+ t2.callExpression(t2.identifier(baseName2), [lowerTrackedExpression(instr.value, ctx)])
21204
+ )
21047
21205
  );
21048
21206
  }
21049
- return t2.expressionStatement(
21050
- t2.assignmentExpression("=", t2.identifier(baseName2), lowerTrackedExpression(instr.value, ctx))
21207
+ return applyLoc(
21208
+ t2.expressionStatement(
21209
+ t2.assignmentExpression(
21210
+ "=",
21211
+ t2.identifier(baseName2),
21212
+ lowerTrackedExpression(instr.value, ctx)
21213
+ )
21214
+ )
21051
21215
  );
21052
21216
  }
21053
21217
  if (instr.kind === "Expression") {
21054
- return t2.expressionStatement(lowerTrackedExpression(instr.value, ctx));
21218
+ return applyLoc(t2.expressionStatement(lowerTrackedExpression(instr.value, ctx)));
21055
21219
  }
21056
21220
  if (instr.kind === "Phi") {
21057
21221
  return null;
@@ -21060,6 +21224,9 @@ function lowerInstruction(instr, ctx) {
21060
21224
  }
21061
21225
  function lowerTerminator(block, ctx) {
21062
21226
  const { t: t2 } = ctx;
21227
+ const baseLoc = block.terminator.loc ?? // eslint-disable-next-line @typescript-eslint/no-explicit-any
21228
+ block.terminator.argument?.loc;
21229
+ const applyLoc = (stmts) => stmts.map((stmt) => setNodeLoc(stmt, baseLoc));
21063
21230
  switch (block.terminator.kind) {
21064
21231
  case "Return": {
21065
21232
  const prevRegion = ctx.currentRegion;
@@ -21072,14 +21239,14 @@ function lowerTerminator(block, ctx) {
21072
21239
  }
21073
21240
  ctx.inReturn = false;
21074
21241
  ctx.currentRegion = prevRegion;
21075
- return [t2.returnStatement(retExpr)];
21242
+ return applyLoc([t2.returnStatement(retExpr)]);
21076
21243
  }
21077
21244
  case "Throw":
21078
- return [t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))];
21245
+ return applyLoc([t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))]);
21079
21246
  case "Jump":
21080
- return [t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))];
21247
+ return applyLoc([t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))]);
21081
21248
  case "Branch":
21082
- return [
21249
+ return applyLoc([
21083
21250
  t2.ifStatement(
21084
21251
  lowerTrackedExpression(block.terminator.test, ctx),
21085
21252
  t2.blockStatement([
@@ -21089,9 +21256,9 @@ function lowerTerminator(block, ctx) {
21089
21256
  t2.expressionStatement(t2.stringLiteral(`goto ${block.terminator.alternate}`))
21090
21257
  ])
21091
21258
  )
21092
- ];
21259
+ ]);
21093
21260
  case "Switch":
21094
- return [
21261
+ return applyLoc([
21095
21262
  t2.switchStatement(
21096
21263
  lowerTrackedExpression(block.terminator.discriminant, ctx),
21097
21264
  block.terminator.cases.map(
@@ -21100,30 +21267,30 @@ function lowerTerminator(block, ctx) {
21100
21267
  ])
21101
21268
  )
21102
21269
  )
21103
- ];
21270
+ ]);
21104
21271
  case "ForOf": {
21105
21272
  const term = block.terminator;
21106
21273
  const varKind = term.variableKind ?? "const";
21107
21274
  const leftPattern = term.pattern ? term.pattern : t2.identifier(term.variable);
21108
- return [
21275
+ return applyLoc([
21109
21276
  t2.forOfStatement(
21110
21277
  t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
21111
21278
  lowerExpression(term.iterable, ctx),
21112
21279
  t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
21113
21280
  )
21114
- ];
21281
+ ]);
21115
21282
  }
21116
21283
  case "ForIn": {
21117
21284
  const term = block.terminator;
21118
21285
  const varKind = term.variableKind ?? "const";
21119
21286
  const leftPattern = term.pattern ? term.pattern : t2.identifier(term.variable);
21120
- return [
21287
+ return applyLoc([
21121
21288
  t2.forInStatement(
21122
21289
  t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
21123
21290
  lowerExpression(term.object, ctx),
21124
21291
  t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
21125
21292
  )
21126
- ];
21293
+ ]);
21127
21294
  }
21128
21295
  case "Try": {
21129
21296
  const term = block.terminator;
@@ -21139,20 +21306,20 @@ function lowerTerminator(block, ctx) {
21139
21306
  const finallyBlock = term.finallyBlock !== void 0 ? t2.blockStatement([
21140
21307
  t2.expressionStatement(t2.stringLiteral(`finally ${term.finallyBlock}`))
21141
21308
  ]) : null;
21142
- return [t2.tryStatement(tryBlock, catchClause, finallyBlock)];
21309
+ return applyLoc([t2.tryStatement(tryBlock, catchClause, finallyBlock)]);
21143
21310
  }
21144
21311
  case "Unreachable":
21145
- return [];
21312
+ return applyLoc([]);
21146
21313
  case "Break":
21147
- return [
21314
+ return applyLoc([
21148
21315
  t2.breakStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
21149
- ];
21316
+ ]);
21150
21317
  case "Continue":
21151
- return [
21318
+ return applyLoc([
21152
21319
  t2.continueStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
21153
- ];
21320
+ ]);
21154
21321
  default:
21155
- return [];
21322
+ return applyLoc([]);
21156
21323
  }
21157
21324
  }
21158
21325
  function attachHelperImports(ctx, body, t2) {
@@ -21291,12 +21458,12 @@ function lowerExpression(expr, ctx, isAssigned = false) {
21291
21458
  }
21292
21459
  ctx.expressionDepth = depth;
21293
21460
  try {
21294
- return lowerExpressionImpl(expr, ctx, isAssigned);
21461
+ return setNodeLoc(lowerExpressionImpl(expr, ctx, isAssigned), expr.loc);
21295
21462
  } finally {
21296
21463
  ctx.expressionDepth = depth - 1;
21297
21464
  }
21298
21465
  }
21299
- function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21466
+ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21300
21467
  const { t: t2 } = ctx;
21301
21468
  const mapParams = (params) => params.map((p) => t2.identifier(deSSAVarName(p.name)));
21302
21469
  const withFunctionScope = (paramNames, fn) => {
@@ -21358,11 +21525,7 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21358
21525
  };
21359
21526
  const declared = new Set(paramIds.map((p) => p.name));
21360
21527
  return lowerStructuredNodeWithoutRegions(structured, t2, ctx, declared);
21361
- } catch (e) {
21362
- console.log(
21363
- "[DEBUG] Structurization failed, falling back to lowerBlocksToStatements via lowerInstruction",
21364
- e
21365
- );
21528
+ } catch {
21366
21529
  return lowerBlocksToStatements(blocks);
21367
21530
  }
21368
21531
  };
@@ -21426,14 +21589,22 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21426
21589
  const calleeIsMemoAccessor = !!calleeName && ctx.memoVars?.has(calleeName);
21427
21590
  const calleeIsSignalLike = !!calleeName && (ctx.signalVars?.has(calleeName) || ctx.storeVars?.has(calleeName));
21428
21591
  if (calleeIsMemoAccessor && !calleeIsSignalLike && expr.arguments.length > 0) {
21429
- const loweredArgs = expr.arguments.map((a) => lowerExpression(a, ctx));
21430
- return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs);
21592
+ const loweredArgs2 = expr.arguments.map((a) => lowerExpression(a, ctx));
21593
+ return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs2);
21431
21594
  }
21432
21595
  const lowerCallee = () => isIIFE ? withNonReactiveScope(ctx, () => lowerExpression(expr.callee, ctx)) : lowerExpression(expr.callee, ctx);
21433
- return t2.callExpression(
21434
- lowerCallee(),
21435
- expr.arguments.map((a) => lowerExpression(a, ctx))
21436
- );
21596
+ const isIteratingMethod = expr.callee.kind === "MemberExpression" && (expr.callee.property.kind === "Identifier" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
21597
+ expr.callee.property.name
21598
+ ) || expr.callee.property.kind === "Literal" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
21599
+ String(expr.callee.property.value)
21600
+ ));
21601
+ const loweredArgs = expr.arguments.map((a, idx) => {
21602
+ if (idx === 0 && isIteratingMethod && (a.kind === "ArrowFunction" || a.kind === "FunctionExpression")) {
21603
+ return withNoMemoAndDynamicHooks(ctx, () => lowerExpression(a, ctx));
21604
+ }
21605
+ return lowerExpression(a, ctx);
21606
+ });
21607
+ return t2.callExpression(lowerCallee(), loweredArgs);
21437
21608
  }
21438
21609
  case "MemberExpression":
21439
21610
  if (matchesListKeyPattern(expr, ctx)) {
@@ -21533,12 +21704,10 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21533
21704
  case "ArrowFunction": {
21534
21705
  const paramIds = mapParams(expr.params);
21535
21706
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
21536
- return withFunctionScope(shadowed, () => {
21537
- if (isAssigned) {
21538
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) + 1;
21539
- }
21540
- let fn;
21541
- try {
21707
+ return withNonReactiveScope(
21708
+ ctx,
21709
+ () => withFunctionScope(shadowed, () => {
21710
+ let fn;
21542
21711
  if (expr.isExpression && !Array.isArray(expr.body)) {
21543
21712
  const { result: bodyExpr, cacheDeclarations } = withGetterCache(
21544
21713
  ctx,
@@ -21566,12 +21735,8 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21566
21735
  }
21567
21736
  fn.async = expr.isAsync ?? false;
21568
21737
  return fn;
21569
- } finally {
21570
- if (isAssigned) {
21571
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) - 1;
21572
- }
21573
- }
21574
- });
21738
+ })
21739
+ );
21575
21740
  }
21576
21741
  case "FunctionExpression": {
21577
21742
  const paramIds = mapParams(expr.params);
@@ -22290,15 +22455,6 @@ function isStaticValue(expr) {
22290
22455
  if (!expr) return false;
22291
22456
  return expr.kind === "Literal";
22292
22457
  }
22293
- function isComponentLikeCallee(expr) {
22294
- if (expr.kind === "Identifier") {
22295
- return expr.name[0] === expr.name[0]?.toUpperCase();
22296
- }
22297
- if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
22298
- return isComponentLikeCallee(expr.object);
22299
- }
22300
- return false;
22301
- }
22302
22458
  function isLikelyTextExpression(expr, ctx) {
22303
22459
  let ok = true;
22304
22460
  const isReactiveIdentifier = (name) => {
@@ -22327,15 +22483,9 @@ function isLikelyTextExpression(expr, ctx) {
22327
22483
  ok = false;
22328
22484
  return;
22329
22485
  case "CallExpression":
22330
- case "OptionalCallExpression": {
22331
- if (isComponentLikeCallee(node.callee)) {
22332
- ok = false;
22333
- return;
22334
- }
22335
- visit(node.callee, true);
22336
- node.arguments.forEach((arg) => visit(arg));
22486
+ case "OptionalCallExpression":
22487
+ ok = false;
22337
22488
  return;
22338
- }
22339
22489
  case "MemberExpression":
22340
22490
  case "OptionalMemberExpression":
22341
22491
  visit(node.object, true);
@@ -22767,16 +22917,28 @@ function lowerIntrinsicElement(jsx, ctx) {
22767
22917
  t2.expressionStatement(lowerDomExpression(binding.expr, ctx, containingRegion))
22768
22918
  );
22769
22919
  } else if (binding.type === "text" && binding.expr) {
22770
- ctx.helpersUsed.add("bindText");
22771
22920
  const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion);
22772
- statements.push(
22773
- t2.expressionStatement(
22774
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22775
- targetId,
22776
- t2.arrowFunctionExpression([], valueExpr)
22777
- ])
22778
- )
22779
- );
22921
+ if (isExpressionReactive(binding.expr, ctx)) {
22922
+ ctx.helpersUsed.add("bindText");
22923
+ statements.push(
22924
+ t2.expressionStatement(
22925
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22926
+ targetId,
22927
+ t2.arrowFunctionExpression([], valueExpr)
22928
+ ])
22929
+ )
22930
+ );
22931
+ } else {
22932
+ statements.push(
22933
+ t2.expressionStatement(
22934
+ t2.assignmentExpression(
22935
+ "=",
22936
+ t2.memberExpression(targetId, t2.identifier("data")),
22937
+ t2.callExpression(t2.identifier("String"), [valueExpr])
22938
+ )
22939
+ )
22940
+ );
22941
+ }
22780
22942
  } else if (binding.type === "child" && binding.expr) {
22781
22943
  emitHIRChildBinding(targetId, binding.expr, statements, ctx, containingRegion);
22782
22944
  }
@@ -22790,7 +22952,12 @@ function lowerIntrinsicElement(jsx, ctx) {
22790
22952
  t2.arrowFunctionExpression([], body)
22791
22953
  ];
22792
22954
  if (ctx.isComponentFn) {
22793
- memoArgs.push(t2.numericLiteral(reserveHookSlot2(ctx)));
22955
+ {
22956
+ const slot = reserveHookSlot2(ctx);
22957
+ if (slot >= 0) {
22958
+ memoArgs.push(t2.numericLiteral(slot));
22959
+ }
22960
+ }
22794
22961
  }
22795
22962
  return t2.callExpression(t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs), []);
22796
22963
  }
@@ -23085,8 +23252,13 @@ function getTrackedCallIdentifier(expr, ctx, itemParamName) {
23085
23252
  }
23086
23253
  return null;
23087
23254
  }
23088
- function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23255
+ function rewriteSelectorExpression(expr, itemParamName, keyParamName, getSelectorId, ctx) {
23089
23256
  const { t: t2 } = ctx;
23257
+ const usesParamIdentifier = (e) => {
23258
+ if (expressionUsesIdentifier(e, itemParamName, t2)) return true;
23259
+ if (keyParamName && expressionUsesIdentifier(e, keyParamName, t2)) return true;
23260
+ return false;
23261
+ };
23090
23262
  if (t2.isBinaryExpression(expr) && (expr.operator === "===" || expr.operator === "==")) {
23091
23263
  const leftTracked = getTrackedCallIdentifier(
23092
23264
  expr.left,
@@ -23098,7 +23270,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23098
23270
  ctx,
23099
23271
  itemParamName
23100
23272
  );
23101
- if (leftTracked && expressionUsesIdentifier(expr.right, itemParamName, t2)) {
23273
+ if (leftTracked && usesParamIdentifier(expr.right)) {
23102
23274
  return {
23103
23275
  expr: t2.callExpression(getSelectorId(leftTracked), [
23104
23276
  expr.right
@@ -23106,7 +23278,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23106
23278
  changed: true
23107
23279
  };
23108
23280
  }
23109
- if (rightTracked && expressionUsesIdentifier(expr.left, itemParamName, t2)) {
23281
+ if (rightTracked && usesParamIdentifier(expr.left)) {
23110
23282
  return {
23111
23283
  expr: t2.callExpression(getSelectorId(rightTracked), [
23112
23284
  expr.left
@@ -23117,7 +23289,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23117
23289
  }
23118
23290
  let changed = false;
23119
23291
  const rewrite = (node) => {
23120
- const result = rewriteSelectorExpression(node, itemParamName, getSelectorId, ctx);
23292
+ const result = rewriteSelectorExpression(node, itemParamName, keyParamName, getSelectorId, ctx);
23121
23293
  if (result.changed) changed = true;
23122
23294
  return result.expr;
23123
23295
  };
@@ -23178,7 +23350,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23178
23350
  }
23179
23351
  return { expr, changed };
23180
23352
  }
23181
- function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23353
+ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statements, ctx) {
23182
23354
  const { t: t2 } = ctx;
23183
23355
  if (!itemParamName) return;
23184
23356
  if (!t2.isArrowFunctionExpression(callbackExpr) && !t2.isFunctionExpression(callbackExpr)) return;
@@ -23194,7 +23366,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23194
23366
  if (t2.isBlockStatement(fn.body)) {
23195
23367
  for (const stmt of fn.body.body) {
23196
23368
  if (t2.isReturnStatement(stmt) && stmt.argument && t2.isExpression(stmt.argument)) {
23197
- const result = rewriteSelectorExpression(stmt.argument, itemParamName, getSelectorId, ctx);
23369
+ const result = rewriteSelectorExpression(
23370
+ stmt.argument,
23371
+ itemParamName,
23372
+ keyParamName,
23373
+ getSelectorId,
23374
+ ctx
23375
+ );
23198
23376
  if (result.changed) {
23199
23377
  stmt.argument = result.expr;
23200
23378
  }
@@ -23203,7 +23381,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23203
23381
  return;
23204
23382
  }
23205
23383
  if (t2.isExpression(fn.body)) {
23206
- const result = rewriteSelectorExpression(fn.body, itemParamName, getSelectorId, ctx);
23384
+ const result = rewriteSelectorExpression(
23385
+ fn.body,
23386
+ itemParamName,
23387
+ keyParamName,
23388
+ getSelectorId,
23389
+ ctx
23390
+ );
23207
23391
  if (result.changed) {
23208
23392
  fn.body = result.expr;
23209
23393
  }
@@ -23345,12 +23529,16 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23345
23529
  const hoistedStatements = ctx.hoistedTemplateStatements;
23346
23530
  ctx.hoistedTemplates = prevHoistedTemplates;
23347
23531
  ctx.hoistedTemplateStatements = prevHoistedTemplateStatements;
23348
- if (isKeyed && (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr))) {
23349
- const firstParam = callbackExpr.params[0];
23532
+ if (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) {
23533
+ const [firstParam, secondParam] = callbackExpr.params;
23534
+ const overrides = {};
23350
23535
  if (t2.isIdentifier(firstParam)) {
23351
- const overrides = {
23352
- [firstParam.name]: () => t2.callExpression(t2.identifier(firstParam.name), [])
23353
- };
23536
+ overrides[firstParam.name] = () => t2.callExpression(t2.identifier(firstParam.name), []);
23537
+ }
23538
+ if (t2.isIdentifier(secondParam)) {
23539
+ overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
23540
+ }
23541
+ if (Object.keys(overrides).length > 0) {
23354
23542
  if (t2.isBlockStatement(callbackExpr.body)) {
23355
23543
  replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
23356
23544
  } else {
@@ -23363,7 +23551,14 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23363
23551
  const listId = genTemp(ctx, "list");
23364
23552
  if (isKeyed) {
23365
23553
  const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : null : null;
23366
- applySelectorHoist(callbackExpr, itemParamName, statements, ctx);
23554
+ const keyParamName = ctx.listKeyParamName ?? null;
23555
+ applySelectorHoist(
23556
+ callbackExpr,
23557
+ itemParamName,
23558
+ keyParamName,
23559
+ statements,
23560
+ ctx
23561
+ );
23367
23562
  }
23368
23563
  if (isKeyed && keyExpr) {
23369
23564
  let keyExprAst = lowerExpression(keyExpr, ctx);
@@ -24244,10 +24439,9 @@ function lowerFunctionWithRegions(fn, ctx) {
24244
24439
  }
24245
24440
  }
24246
24441
  const params = finalParams;
24247
- const funcDecl = t2.functionDeclaration(
24248
- t2.identifier(fn.name ?? "fn"),
24249
- params,
24250
- t2.blockStatement(statements)
24442
+ const funcDecl = setNodeLoc(
24443
+ t2.functionDeclaration(t2.identifier(fn.name ?? "fn"), params, t2.blockStatement(statements)),
24444
+ fn.loc
24251
24445
  );
24252
24446
  ctx.needsCtx = prevNeedsCtx;
24253
24447
  ctx.shadowedNames = prevShadowed;
@@ -24336,10 +24530,44 @@ function isInsideNestedFunction(path) {
24336
24530
  function isInsideJSX(path) {
24337
24531
  return !!path.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
24338
24532
  }
24339
- function emitWarning(node, code, message, options, fileName) {
24340
- if (!options.onWarn) return;
24533
+ function parseSuppressionCodes(raw) {
24534
+ if (!raw) return void 0;
24535
+ const codes = raw.split(/[,\s]+/).map((c) => c.trim()).filter(Boolean);
24536
+ return codes.length > 0 ? new Set(codes) : void 0;
24537
+ }
24538
+ function parseSuppressions(comments) {
24539
+ if (!comments) return [];
24540
+ const suppressions = [];
24541
+ for (const comment of comments) {
24542
+ const match = comment.value.match(/fict-ignore(-next-line)?(?:\s+(.+))?/i);
24543
+ if (!match || !comment.loc) continue;
24544
+ suppressions.push({
24545
+ line: comment.loc.start.line,
24546
+ nextLine: !!match[1],
24547
+ codes: parseSuppressionCodes(match[2])
24548
+ });
24549
+ }
24550
+ return suppressions;
24551
+ }
24552
+ function shouldSuppressWarning(suppressions, code, line) {
24553
+ return suppressions.some((entry) => {
24554
+ const targetLine = entry.nextLine ? entry.line + 1 : entry.line;
24555
+ if (targetLine !== line) return false;
24556
+ if (!entry.codes || entry.codes.size === 0) return true;
24557
+ return entry.codes.has(code);
24558
+ });
24559
+ }
24560
+ function createWarningDispatcher(onWarn, suppressions) {
24561
+ if (!onWarn) return () => {
24562
+ };
24563
+ return (warning) => {
24564
+ if (shouldSuppressWarning(suppressions, warning.code, warning.line)) return;
24565
+ onWarn(warning);
24566
+ };
24567
+ }
24568
+ function emitWarning(node, code, message, warn, fileName) {
24341
24569
  const loc = node.loc?.start;
24342
- options.onWarn({
24570
+ warn({
24343
24571
  code,
24344
24572
  message,
24345
24573
  fileName,
@@ -24427,8 +24655,7 @@ function isDynamicPropertyAccess(node, t2) {
24427
24655
  if (!node.computed) return false;
24428
24656
  return !(t2.isStringLiteral(node.property) || t2.isNumericLiteral(node.property));
24429
24657
  }
24430
- function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24431
- const fileName = programPath.hub?.file?.opts?.filename || "<unknown>";
24658
+ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t2) {
24432
24659
  const isStateRoot = (expr) => {
24433
24660
  const root = getRootIdentifier(expr, t2);
24434
24661
  return !!(root && stateVars.has(root.name));
@@ -24444,7 +24671,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24444
24671
  path.node,
24445
24672
  "FICT-M",
24446
24673
  "Direct mutation of nested property detected; use immutable update or $store helpers",
24447
- options,
24674
+ warn,
24448
24675
  fileName
24449
24676
  );
24450
24677
  if (isDynamicPropertyAccess(left, t2)) {
@@ -24452,7 +24679,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24452
24679
  path.node,
24453
24680
  "FICT-H",
24454
24681
  "Dynamic property access widens dependency tracking",
24455
- options,
24682
+ warn,
24456
24683
  fileName
24457
24684
  );
24458
24685
  }
@@ -24467,7 +24694,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24467
24694
  path.node,
24468
24695
  "FICT-M",
24469
24696
  "Direct mutation of nested property detected; use immutable update or $store helpers",
24470
- options,
24697
+ warn,
24471
24698
  fileName
24472
24699
  );
24473
24700
  if (isDynamicPropertyAccess(arg, t2)) {
@@ -24475,7 +24702,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24475
24702
  path.node,
24476
24703
  "FICT-H",
24477
24704
  "Dynamic property access widens dependency tracking",
24478
- options,
24705
+ warn,
24479
24706
  fileName
24480
24707
  );
24481
24708
  }
@@ -24491,7 +24718,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24491
24718
  path.node,
24492
24719
  "FICT-H",
24493
24720
  "Dynamic property access widens dependency tracking",
24494
- options,
24721
+ warn,
24495
24722
  fileName
24496
24723
  );
24497
24724
  }
@@ -24520,7 +24747,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24520
24747
  path.node,
24521
24748
  "FICT-R005",
24522
24749
  `Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
24523
- options,
24750
+ warn,
24524
24751
  fileName
24525
24752
  );
24526
24753
  }
@@ -24551,7 +24778,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24551
24778
  path.node,
24552
24779
  "FICT-E001",
24553
24780
  "Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
24554
- options,
24781
+ warn,
24555
24782
  fileName
24556
24783
  );
24557
24784
  }
@@ -24577,7 +24804,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24577
24804
  arg,
24578
24805
  "FICT-H",
24579
24806
  "State value passed to unknown function (black box); dependency tracking may be imprecise",
24580
- options,
24807
+ warn,
24581
24808
  fileName
24582
24809
  );
24583
24810
  break;
@@ -24593,7 +24820,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24593
24820
  path.node,
24594
24821
  "FICT-H",
24595
24822
  "Dynamic property access widens dependency tracking",
24596
- options,
24823
+ warn,
24597
24824
  fileName
24598
24825
  );
24599
24826
  }
@@ -24643,6 +24870,10 @@ function createHIREntrypointVisitor(t2, options) {
24643
24870
  Program: {
24644
24871
  exit(path) {
24645
24872
  const fileName = path.hub?.file?.opts?.filename || "<unknown>";
24873
+ const comments = path.hub?.file?.ast?.comments || [];
24874
+ const suppressions = parseSuppressions(comments);
24875
+ const warn = createWarningDispatcher(options.onWarn, suppressions);
24876
+ const optionsWithWarnings = { ...options, onWarn: warn };
24646
24877
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
24647
24878
  const getFunctionName = (fnPath) => {
24648
24879
  return fnPath.isFunctionDeclaration() && fnPath.node.id ? fnPath.node.id.name : fnPath.isFunctionExpression() && fnPath.node.id ? fnPath.node.id.name : fnPath.parentPath.isVariableDeclarator() && t2.isIdentifier(fnPath.parentPath.node.id) && fnPath.parentPath.node.init === fnPath.node ? fnPath.parentPath.node.id.name : void 0;
@@ -24661,14 +24892,75 @@ function createHIREntrypointVisitor(t2, options) {
24661
24892
  return name && isComponentName(name) || isHookName2(name) || functionHasJSX(fnPath) || functionUsesStateLike(fnPath, t2);
24662
24893
  };
24663
24894
  const memoHasSideEffects = (fn) => {
24895
+ const pureCalls = new Set(
24896
+ Array.from(SAFE_FUNCTIONS).filter(
24897
+ (name) => !name.startsWith("console.") && name !== "Math.random"
24898
+ )
24899
+ );
24900
+ const effectfulCalls = /* @__PURE__ */ new Set([
24901
+ "$effect",
24902
+ "render",
24903
+ "fetch",
24904
+ "setTimeout",
24905
+ "setInterval",
24906
+ "clearTimeout",
24907
+ "clearInterval",
24908
+ "requestAnimationFrame",
24909
+ "cancelAnimationFrame"
24910
+ ]);
24911
+ const getCalleeName = (callee) => {
24912
+ if (t2.isIdentifier(callee)) return callee.name;
24913
+ if (t2.isMemberExpression(callee) && !callee.computed && t2.isIdentifier(callee.property) && t2.isIdentifier(callee.object)) {
24914
+ return `${callee.object.name}.${callee.property.name}`;
24915
+ }
24916
+ return null;
24917
+ };
24918
+ const mutatingMemberProps = /* @__PURE__ */ new Set([
24919
+ "push",
24920
+ "pop",
24921
+ "splice",
24922
+ "shift",
24923
+ "unshift",
24924
+ "sort",
24925
+ "reverse",
24926
+ "set",
24927
+ "add",
24928
+ "delete",
24929
+ "append",
24930
+ "appendChild",
24931
+ "remove",
24932
+ "removeChild",
24933
+ "setAttribute",
24934
+ "dispatchEvent",
24935
+ "replaceChildren",
24936
+ "replaceWith"
24937
+ ]);
24938
+ const isEffectfulCall = (node) => {
24939
+ const name = getCalleeName(node.callee);
24940
+ if (!name) return true;
24941
+ if (pureCalls.has(name)) return false;
24942
+ if (effectfulCalls.has(name)) return true;
24943
+ if (name.startsWith("console.") || name.startsWith("document.") || name.startsWith("window.")) {
24944
+ return true;
24945
+ }
24946
+ if (t2.isMemberExpression(node.callee) && !node.callee.computed && t2.isIdentifier(node.callee.property)) {
24947
+ const prop = node.callee.property.name;
24948
+ if (mutatingMemberProps.has(prop)) return true;
24949
+ if (t2.isIdentifier(node.callee.object) && (node.callee.object.name === "document" || node.callee.object.name === "window")) {
24950
+ return true;
24951
+ }
24952
+ }
24953
+ return false;
24954
+ };
24664
24955
  const checkNode = (node) => {
24665
24956
  if (!node) return false;
24666
24957
  if (t2.isAssignmentExpression(node) || t2.isUpdateExpression(node) || t2.isThrowStatement(node) || t2.isNewExpression(node)) {
24667
24958
  return true;
24668
24959
  }
24669
- if (t2.isCallExpression(node) && (t2.isIdentifier(node.callee) && node.callee.name === "$effect" || t2.isIdentifier(node.callee) && node.callee.name === "render")) {
24960
+ if (t2.isCallExpression(node) && isEffectfulCall(node)) {
24670
24961
  return true;
24671
24962
  }
24963
+ if (t2.isAwaitExpression(node)) return true;
24672
24964
  if (t2.isExpressionStatement(node)) return checkNode(node.expression);
24673
24965
  if (t2.isBlockStatement(node)) return node.body.some((stmt) => checkNode(stmt));
24674
24966
  if (t2.isReturnStatement(node)) return checkNode(node.argument);
@@ -24692,7 +24984,7 @@ function createHIREntrypointVisitor(t2, options) {
24692
24984
  fnPath.node,
24693
24985
  "FICT-C004",
24694
24986
  "Component has no return statement and will render nothing.",
24695
- options,
24987
+ warn,
24696
24988
  fileName
24697
24989
  );
24698
24990
  },
@@ -24710,7 +25002,7 @@ function createHIREntrypointVisitor(t2, options) {
24710
25002
  init,
24711
25003
  "FICT-C004",
24712
25004
  "Component has no return statement and will render nothing.",
24713
- options,
25005
+ warn,
24714
25006
  fileName
24715
25007
  );
24716
25008
  }
@@ -24760,7 +25052,7 @@ function createHIREntrypointVisitor(t2, options) {
24760
25052
  }
24761
25053
  }
24762
25054
  if (hasKey || hasUnknownSpread) return;
24763
- options.onWarn?.({
25055
+ warn({
24764
25056
  code: "FICT-J002",
24765
25057
  message: "Missing key prop in list rendering.",
24766
25058
  fileName,
@@ -24831,7 +25123,7 @@ function createHIREntrypointVisitor(t2, options) {
24831
25123
  fnPath.node,
24832
25124
  "FICT-C003",
24833
25125
  "Components should not be defined inside other components. Move this definition to module scope to preserve identity and performance.",
24834
- options,
25126
+ warn,
24835
25127
  fileName
24836
25128
  );
24837
25129
  },
@@ -24876,7 +25168,7 @@ function createHIREntrypointVisitor(t2, options) {
24876
25168
  callPath.node,
24877
25169
  "FICT-R004",
24878
25170
  "Reactive creation inside non-JSX control flow will not auto-dispose; wrap it in createScope/runInScope or move it into JSX-managed regions.",
24879
- options,
25171
+ warn,
24880
25172
  fileName
24881
25173
  );
24882
25174
  }
@@ -24911,7 +25203,7 @@ function createHIREntrypointVisitor(t2, options) {
24911
25203
  callPath.node.arguments.forEach((arg) => {
24912
25204
  if (t2.isIdentifier(arg) && stateVars.has(arg.name) && (!calleeId || !allowedStateCallees.has(calleeId))) {
24913
25205
  const loc = arg.loc?.start ?? callPath.node.loc?.start;
24914
- options.onWarn?.({
25206
+ warn({
24915
25207
  code: "FICT-S002",
24916
25208
  message: "State variable is passed as an argument; this passes a value snapshot and may escape component scope.",
24917
25209
  fileName,
@@ -24924,7 +25216,7 @@ function createHIREntrypointVisitor(t2, options) {
24924
25216
  const firstArg = callPath.node.arguments[0];
24925
25217
  if (firstArg && (t2.isArrowFunctionExpression(firstArg) || t2.isFunctionExpression(firstArg)) && memoHasSideEffects(firstArg)) {
24926
25218
  const loc = firstArg.loc?.start ?? callPath.node.loc?.start;
24927
- options.onWarn?.({
25219
+ warn({
24928
25220
  code: "FICT-M003",
24929
25221
  message: "Memo should not contain side effects.",
24930
25222
  fileName,
@@ -25029,10 +25321,10 @@ function createHIREntrypointVisitor(t2, options) {
25029
25321
  }
25030
25322
  });
25031
25323
  }
25032
- runWarningPass(path, stateVars, derivedVars, options, t2);
25324
+ runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25033
25325
  const fileAst = t2.file(path.node);
25034
25326
  const hir = buildHIR(fileAst);
25035
- const lowered = lowerHIRWithRegions(hir, t2, options);
25327
+ const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
25036
25328
  path.node.body = lowered.program.body;
25037
25329
  path.node.directives = lowered.program.directives;
25038
25330
  if (!process.env.FICT_SKIP_SCOPE_CRAWL) {