@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.cjs CHANGED
@@ -14384,6 +14384,9 @@ function pathToString(path) {
14384
14384
 
14385
14385
  // src/ir/build-hir.ts
14386
14386
  var destructuringTempCounter = 0;
14387
+ var getLoc = (node) => {
14388
+ return node?.loc ?? null;
14389
+ };
14387
14390
  function normalizeVarKind(kind) {
14388
14391
  return kind === "const" || kind === "let" || kind === "var" ? kind : "let";
14389
14392
  }
@@ -14453,7 +14456,8 @@ function buildHIR(ast) {
14453
14456
  functions.push(
14454
14457
  convertFunction(name, stmt.params, stmt.body.body, {
14455
14458
  noMemo: programNoMemo,
14456
- directives: stmt.body.directives
14459
+ directives: stmt.body.directives,
14460
+ loc: getLoc(stmt)
14457
14461
  })
14458
14462
  );
14459
14463
  continue;
@@ -14466,7 +14470,8 @@ function buildHIR(ast) {
14466
14470
  functions.push(
14467
14471
  convertFunction(name, decl.params, decl.body.body, {
14468
14472
  noMemo: programNoMemo,
14469
- directives: decl.body.directives
14473
+ directives: decl.body.directives,
14474
+ loc: getLoc(decl)
14470
14475
  })
14471
14476
  );
14472
14477
  postamble.push({ kind: "ExportFunction", name });
@@ -14484,9 +14489,11 @@ function buildHIR(ast) {
14484
14489
  const hasExpressionBody = isArrow && !t.isBlockStatement(body);
14485
14490
  const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
14486
14491
  noMemo: programNoMemo,
14487
- directives: body.directives
14492
+ directives: body.directives,
14493
+ loc: getLoc(v.init ?? v)
14488
14494
  }) : convertFunction(name, params, [t.returnStatement(body)], {
14489
- noMemo: programNoMemo
14495
+ noMemo: programNoMemo,
14496
+ loc: getLoc(v.init ?? v)
14490
14497
  });
14491
14498
  fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
14492
14499
  functions.push(fnHIR);
@@ -14511,7 +14518,8 @@ function buildHIR(ast) {
14511
14518
  functions.push(
14512
14519
  convertFunction(name, decl.params, decl.body.body, {
14513
14520
  noMemo: programNoMemo,
14514
- directives: decl.body.directives
14521
+ directives: decl.body.directives,
14522
+ loc: getLoc(decl)
14515
14523
  })
14516
14524
  );
14517
14525
  postamble.push({ kind: "ExportDefault", name });
@@ -14536,13 +14544,15 @@ function buildHIR(ast) {
14536
14544
  const hasExpressionBody = isArrow && !t.isBlockStatement(body);
14537
14545
  const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
14538
14546
  noMemo: programNoMemo,
14539
- directives: body.directives
14547
+ directives: body.directives,
14548
+ loc: getLoc(decl.init ?? decl)
14540
14549
  }) : convertFunction(
14541
14550
  name,
14542
14551
  params,
14543
14552
  [t.returnStatement(body)],
14544
14553
  {
14545
- noMemo: programNoMemo
14554
+ noMemo: programNoMemo,
14555
+ loc: getLoc(decl.init ?? decl)
14546
14556
  }
14547
14557
  );
14548
14558
  fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
@@ -15050,11 +15060,12 @@ function convertFunction(name, params, body, options) {
15050
15060
  name,
15051
15061
  params: paramIds,
15052
15062
  blocks,
15053
- meta: hasNoMemo ? { noMemo: true } : void 0
15063
+ meta: hasNoMemo ? { noMemo: true } : void 0,
15064
+ loc: options?.loc ?? null
15054
15065
  };
15055
15066
  }
15056
15067
  function convertStatementsToHIRFunction(name, statements) {
15057
- return convertFunction(name, [], statements);
15068
+ return convertFunction(name, [], statements, { loc: getLoc(statements[0]) });
15058
15069
  }
15059
15070
  function convertAssignmentValue(expr) {
15060
15071
  const right = convertExpression(expr.right);
@@ -15552,14 +15563,16 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
15552
15563
  return bb;
15553
15564
  }
15554
15565
  function convertExpression(node) {
15555
- if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name };
15566
+ const loc = getLoc(node);
15567
+ if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name, loc };
15556
15568
  if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node))
15557
- return { kind: "Literal", value: node.value ?? null };
15569
+ return { kind: "Literal", value: node.value ?? null, loc };
15558
15570
  if (t.isCallExpression(node)) {
15559
15571
  const call = {
15560
15572
  kind: "CallExpression",
15561
15573
  callee: convertExpression(node.callee),
15562
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
15574
+ arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15575
+ loc
15563
15576
  };
15564
15577
  return call;
15565
15578
  }
@@ -15574,7 +15587,8 @@ function convertExpression(node) {
15574
15587
  object,
15575
15588
  property,
15576
15589
  computed: node.computed,
15577
- optional: node.optional ?? true
15590
+ optional: node.optional ?? true,
15591
+ loc
15578
15592
  };
15579
15593
  return optionalMember;
15580
15594
  }
@@ -15583,7 +15597,8 @@ function convertExpression(node) {
15583
15597
  object,
15584
15598
  property,
15585
15599
  computed: node.computed,
15586
- optional: false
15600
+ optional: false,
15601
+ loc
15587
15602
  };
15588
15603
  return member;
15589
15604
  }
@@ -15592,7 +15607,8 @@ function convertExpression(node) {
15592
15607
  kind: "BinaryExpression",
15593
15608
  operator: node.operator,
15594
15609
  left: convertExpression(node.left),
15595
- right: convertExpression(node.right)
15610
+ right: convertExpression(node.right),
15611
+ loc
15596
15612
  };
15597
15613
  return bin;
15598
15614
  }
@@ -15601,7 +15617,8 @@ function convertExpression(node) {
15601
15617
  kind: "UnaryExpression",
15602
15618
  operator: node.operator,
15603
15619
  argument: convertExpression(node.argument),
15604
- prefix: node.prefix
15620
+ prefix: node.prefix,
15621
+ loc
15605
15622
  };
15606
15623
  return un;
15607
15624
  }
@@ -15610,7 +15627,8 @@ function convertExpression(node) {
15610
15627
  kind: "LogicalExpression",
15611
15628
  operator: node.operator,
15612
15629
  left: convertExpression(node.left),
15613
- right: convertExpression(node.right)
15630
+ right: convertExpression(node.right),
15631
+ loc
15614
15632
  };
15615
15633
  return log;
15616
15634
  }
@@ -15619,7 +15637,8 @@ function convertExpression(node) {
15619
15637
  kind: "ConditionalExpression",
15620
15638
  test: convertExpression(node.test),
15621
15639
  consequent: convertExpression(node.consequent),
15622
- alternate: convertExpression(node.alternate)
15640
+ alternate: convertExpression(node.alternate),
15641
+ loc
15623
15642
  };
15624
15643
  return cond;
15625
15644
  }
@@ -15631,12 +15650,14 @@ function convertExpression(node) {
15631
15650
  if (t.isSpreadElement(el)) {
15632
15651
  return {
15633
15652
  kind: "SpreadElement",
15634
- argument: convertExpression(el.argument)
15653
+ argument: convertExpression(el.argument),
15654
+ loc: getLoc(el)
15635
15655
  };
15636
15656
  }
15637
15657
  if (t.isExpression(el)) return convertExpression(el);
15638
15658
  return void 0;
15639
- }).filter(Boolean)
15659
+ }).filter(Boolean),
15660
+ loc
15640
15661
  };
15641
15662
  return arr;
15642
15663
  }
@@ -15647,7 +15668,8 @@ function convertExpression(node) {
15647
15668
  if (t.isSpreadElement(prop)) {
15648
15669
  return {
15649
15670
  kind: "SpreadElement",
15650
- argument: convertExpression(prop.argument)
15671
+ argument: convertExpression(prop.argument),
15672
+ loc: getLoc(prop)
15651
15673
  };
15652
15674
  }
15653
15675
  if (t.isObjectMethod(prop)) {
@@ -15664,7 +15686,8 @@ function convertExpression(node) {
15664
15686
  return {
15665
15687
  kind: "Property",
15666
15688
  key: keyExpr2,
15667
- value: convertExpression(fnExpr)
15689
+ value: convertExpression(fnExpr),
15690
+ loc: getLoc(prop)
15668
15691
  };
15669
15692
  }
15670
15693
  if (!t.isObjectProperty(prop) || prop.computed) return void 0;
@@ -15674,9 +15697,12 @@ function convertExpression(node) {
15674
15697
  return {
15675
15698
  kind: "Property",
15676
15699
  key: keyExpr,
15677
- value: convertExpression(prop.value)
15700
+ value: convertExpression(prop.value),
15701
+ shorthand: prop.shorthand && t.isIdentifier(prop.value),
15702
+ loc: getLoc(prop)
15678
15703
  };
15679
- }).filter(Boolean)
15704
+ }).filter(Boolean),
15705
+ loc
15680
15706
  };
15681
15707
  return obj;
15682
15708
  }
@@ -15689,38 +15715,42 @@ function convertExpression(node) {
15689
15715
  if (t.isJSXText(child)) {
15690
15716
  const text = child.value;
15691
15717
  if (text.trim()) {
15692
- children.push({ kind: "text", value: text });
15718
+ children.push({ kind: "text", value: text, loc: getLoc(child) });
15693
15719
  }
15694
15720
  } else if (t.isJSXExpressionContainer(child)) {
15695
15721
  if (!t.isJSXEmptyExpression(child.expression)) {
15696
15722
  children.push({
15697
15723
  kind: "expression",
15698
- value: convertExpression(child.expression)
15724
+ value: convertExpression(child.expression),
15725
+ loc: getLoc(child)
15699
15726
  });
15700
15727
  }
15701
15728
  } else if (t.isJSXElement(child)) {
15702
15729
  children.push({
15703
15730
  kind: "element",
15704
- value: convertJSXElement(child)
15731
+ value: convertJSXElement(child),
15732
+ loc: getLoc(child)
15705
15733
  });
15706
15734
  } else if (t.isJSXFragment(child)) {
15707
15735
  for (const fragChild of child.children) {
15708
15736
  if (t.isJSXText(fragChild)) {
15709
15737
  const text = fragChild.value;
15710
15738
  if (text.trim()) {
15711
- children.push({ kind: "text", value: text });
15739
+ children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
15712
15740
  }
15713
15741
  } else if (t.isJSXExpressionContainer(fragChild)) {
15714
15742
  if (!t.isJSXEmptyExpression(fragChild.expression)) {
15715
15743
  children.push({
15716
15744
  kind: "expression",
15717
- value: convertExpression(fragChild.expression)
15745
+ value: convertExpression(fragChild.expression),
15746
+ loc: getLoc(fragChild)
15718
15747
  });
15719
15748
  }
15720
15749
  } else if (t.isJSXElement(fragChild)) {
15721
15750
  children.push({
15722
15751
  kind: "element",
15723
- value: convertJSXElement(fragChild)
15752
+ value: convertJSXElement(fragChild),
15753
+ loc: getLoc(fragChild)
15724
15754
  });
15725
15755
  }
15726
15756
  }
@@ -15728,24 +15758,27 @@ function convertExpression(node) {
15728
15758
  }
15729
15759
  return {
15730
15760
  kind: "JSXElement",
15731
- tagName: { kind: "Identifier", name: "Fragment" },
15761
+ tagName: { kind: "Identifier", name: "Fragment", loc: getLoc(node) },
15732
15762
  isComponent: true,
15733
15763
  attributes: [],
15734
- children
15764
+ children,
15765
+ loc: getLoc(node)
15735
15766
  };
15736
15767
  }
15737
15768
  if (t.isArrowFunctionExpression(node)) {
15738
15769
  if (t.isBlockStatement(node.body)) {
15739
15770
  const nested = convertFunction(void 0, node.params, node.body.body, {
15740
15771
  noMemo: hasNoMemoDirectiveInStatements(node.body.body),
15741
- directives: node.body.directives
15772
+ directives: node.body.directives,
15773
+ loc: getLoc(node)
15742
15774
  });
15743
15775
  const arrow = {
15744
15776
  kind: "ArrowFunction",
15745
15777
  params: nested.params,
15746
15778
  body: nested.blocks,
15747
15779
  isExpression: false,
15748
- isAsync: node.async
15780
+ isAsync: node.async,
15781
+ loc
15749
15782
  };
15750
15783
  return arrow;
15751
15784
  } else {
@@ -15756,7 +15789,8 @@ function convertExpression(node) {
15756
15789
  ).flat(),
15757
15790
  body: convertExpression(node.body),
15758
15791
  isExpression: true,
15759
- isAsync: node.async
15792
+ isAsync: node.async,
15793
+ loc
15760
15794
  };
15761
15795
  return arrow;
15762
15796
  }
@@ -15764,14 +15798,16 @@ function convertExpression(node) {
15764
15798
  if (t.isFunctionExpression(node)) {
15765
15799
  const nested = convertFunction(void 0, node.params, node.body.body, {
15766
15800
  noMemo: hasNoMemoDirectiveInStatements(node.body.body),
15767
- directives: node.body.directives
15801
+ directives: node.body.directives,
15802
+ loc: getLoc(node)
15768
15803
  });
15769
15804
  const fn = {
15770
15805
  kind: "FunctionExpression",
15771
15806
  name: node.id?.name ?? "",
15772
15807
  params: nested.params,
15773
15808
  body: nested.blocks,
15774
- isAsync: node.async
15809
+ isAsync: node.async,
15810
+ loc
15775
15811
  };
15776
15812
  return fn;
15777
15813
  }
@@ -15780,7 +15816,8 @@ function convertExpression(node) {
15780
15816
  kind: "AssignmentExpression",
15781
15817
  operator: node.operator,
15782
15818
  left: convertExpression(node.left),
15783
- right: convertExpression(node.right)
15819
+ right: convertExpression(node.right),
15820
+ loc
15784
15821
  };
15785
15822
  return assign;
15786
15823
  }
@@ -15789,7 +15826,8 @@ function convertExpression(node) {
15789
15826
  kind: "UpdateExpression",
15790
15827
  operator: node.operator,
15791
15828
  argument: convertExpression(node.argument),
15792
- prefix: node.prefix
15829
+ prefix: node.prefix,
15830
+ loc
15793
15831
  };
15794
15832
  return update;
15795
15833
  }
@@ -15797,34 +15835,39 @@ function convertExpression(node) {
15797
15835
  const template = {
15798
15836
  kind: "TemplateLiteral",
15799
15837
  quasis: node.quasis.map((q) => q.value.cooked ?? q.value.raw),
15800
- expressions: node.expressions.map((e) => convertExpression(e))
15838
+ expressions: node.expressions.map((e) => convertExpression(e)),
15839
+ loc
15801
15840
  };
15802
15841
  return template;
15803
15842
  }
15804
15843
  if (t.isAwaitExpression(node)) {
15805
15844
  return {
15806
15845
  kind: "AwaitExpression",
15807
- argument: convertExpression(node.argument)
15846
+ argument: convertExpression(node.argument),
15847
+ loc
15808
15848
  };
15809
15849
  }
15810
15850
  if (t.isNewExpression(node)) {
15811
15851
  return {
15812
15852
  kind: "NewExpression",
15813
15853
  callee: convertExpression(node.callee),
15814
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
15854
+ arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15855
+ loc
15815
15856
  };
15816
15857
  }
15817
15858
  if (t.isSequenceExpression(node)) {
15818
15859
  return {
15819
15860
  kind: "SequenceExpression",
15820
- expressions: node.expressions.map((e) => convertExpression(e))
15861
+ expressions: node.expressions.map((e) => convertExpression(e)),
15862
+ loc
15821
15863
  };
15822
15864
  }
15823
15865
  if (t.isYieldExpression(node)) {
15824
15866
  return {
15825
15867
  kind: "YieldExpression",
15826
15868
  argument: node.argument ? convertExpression(node.argument) : null,
15827
- delegate: node.delegate
15869
+ delegate: node.delegate,
15870
+ loc
15828
15871
  };
15829
15872
  }
15830
15873
  if (t.isOptionalCallExpression(node)) {
@@ -15832,7 +15875,8 @@ function convertExpression(node) {
15832
15875
  kind: "OptionalCallExpression",
15833
15876
  callee: convertExpression(node.callee),
15834
15877
  arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15835
- optional: node.optional
15878
+ optional: node.optional,
15879
+ loc
15836
15880
  };
15837
15881
  }
15838
15882
  if (t.isTaggedTemplateExpression(node)) {
@@ -15844,8 +15888,10 @@ function convertExpression(node) {
15844
15888
  quasis: node.quasi.quasis.map((q) => q.value.cooked ?? q.value.raw),
15845
15889
  expressions: node.quasi.expressions.map(
15846
15890
  (e) => convertExpression(e)
15847
- )
15848
- }
15891
+ ),
15892
+ loc: getLoc(node.quasi)
15893
+ },
15894
+ loc
15849
15895
  };
15850
15896
  }
15851
15897
  if (t.isClassExpression(node)) {
@@ -15853,17 +15899,18 @@ function convertExpression(node) {
15853
15899
  kind: "ClassExpression",
15854
15900
  name: node.id?.name,
15855
15901
  superClass: node.superClass ? convertExpression(node.superClass) : void 0,
15856
- body: node.body.body
15902
+ body: node.body.body,
15857
15903
  // Store as Babel AST for now
15904
+ loc
15858
15905
  };
15859
15906
  }
15860
15907
  if (t.isThisExpression(node)) {
15861
- return { kind: "ThisExpression" };
15908
+ return { kind: "ThisExpression", loc };
15862
15909
  }
15863
15910
  if (t.isSuper(node)) {
15864
- return { kind: "SuperExpression" };
15911
+ return { kind: "SuperExpression", loc };
15865
15912
  }
15866
- const fallback = { kind: "Literal", value: void 0 };
15913
+ const fallback = { kind: "Literal", value: void 0, loc };
15867
15914
  return fallback;
15868
15915
  }
15869
15916
  function convertJSXElement(node) {
@@ -15874,7 +15921,7 @@ function convertJSXElement(node) {
15874
15921
  const name = opening.name.name;
15875
15922
  const firstChar = name[0];
15876
15923
  if (firstChar && firstChar === firstChar.toUpperCase()) {
15877
- tagName = { kind: "Identifier", name };
15924
+ tagName = { kind: "Identifier", name, loc: getLoc(opening.name) };
15878
15925
  isComponent = true;
15879
15926
  } else {
15880
15927
  tagName = name;
@@ -15892,20 +15939,22 @@ function convertJSXElement(node) {
15892
15939
  name: "",
15893
15940
  value: null,
15894
15941
  isSpread: true,
15895
- spreadExpr: convertExpression(attr.argument)
15942
+ spreadExpr: convertExpression(attr.argument),
15943
+ loc: getLoc(attr)
15896
15944
  });
15897
15945
  } else if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
15898
15946
  let value = null;
15899
15947
  if (attr.value) {
15900
15948
  if (t.isStringLiteral(attr.value)) {
15901
- value = { kind: "Literal", value: attr.value.value };
15949
+ value = { kind: "Literal", value: attr.value.value, loc: getLoc(attr.value) };
15902
15950
  } else if (t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
15903
15951
  value = convertExpression(attr.value.expression);
15904
15952
  }
15905
15953
  }
15906
15954
  attributes.push({
15907
15955
  name: attr.name.name,
15908
- value
15956
+ value,
15957
+ loc: getLoc(attr)
15909
15958
  });
15910
15959
  }
15911
15960
  }
@@ -15914,38 +15963,42 @@ function convertJSXElement(node) {
15914
15963
  if (t.isJSXText(child)) {
15915
15964
  const text = child.value;
15916
15965
  if (text.trim()) {
15917
- children.push({ kind: "text", value: text });
15966
+ children.push({ kind: "text", value: text, loc: getLoc(child) });
15918
15967
  }
15919
15968
  } else if (t.isJSXExpressionContainer(child)) {
15920
15969
  if (!t.isJSXEmptyExpression(child.expression)) {
15921
15970
  children.push({
15922
15971
  kind: "expression",
15923
- value: convertExpression(child.expression)
15972
+ value: convertExpression(child.expression),
15973
+ loc: getLoc(child)
15924
15974
  });
15925
15975
  }
15926
15976
  } else if (t.isJSXElement(child)) {
15927
15977
  children.push({
15928
15978
  kind: "element",
15929
- value: convertJSXElement(child)
15979
+ value: convertJSXElement(child),
15980
+ loc: getLoc(child)
15930
15981
  });
15931
15982
  } else if (t.isJSXFragment(child)) {
15932
15983
  for (const fragChild of child.children) {
15933
15984
  if (t.isJSXText(fragChild)) {
15934
15985
  const text = fragChild.value;
15935
15986
  if (text.trim()) {
15936
- children.push({ kind: "text", value: text });
15987
+ children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
15937
15988
  }
15938
15989
  } else if (t.isJSXExpressionContainer(fragChild)) {
15939
15990
  if (!t.isJSXEmptyExpression(fragChild.expression)) {
15940
15991
  children.push({
15941
15992
  kind: "expression",
15942
- value: convertExpression(fragChild.expression)
15993
+ value: convertExpression(fragChild.expression),
15994
+ loc: getLoc(fragChild)
15943
15995
  });
15944
15996
  }
15945
15997
  } else if (t.isJSXElement(fragChild)) {
15946
15998
  children.push({
15947
15999
  kind: "element",
15948
- value: convertJSXElement(fragChild)
16000
+ value: convertJSXElement(fragChild),
16001
+ loc: getLoc(fragChild)
15949
16002
  });
15950
16003
  }
15951
16004
  }
@@ -15956,21 +16009,27 @@ function convertJSXElement(node) {
15956
16009
  tagName,
15957
16010
  isComponent,
15958
16011
  attributes,
15959
- children
16012
+ children,
16013
+ loc: getLoc(node)
15960
16014
  };
15961
16015
  }
15962
16016
  function convertJSXMemberExpr(node) {
15963
16017
  let object;
15964
16018
  if (t.isJSXIdentifier(node.object)) {
15965
- object = { kind: "Identifier", name: node.object.name };
16019
+ object = { kind: "Identifier", name: node.object.name, loc: getLoc(node.object) };
15966
16020
  } else {
15967
16021
  object = convertJSXMemberExpr(node.object);
15968
16022
  }
15969
16023
  return {
15970
16024
  kind: "MemberExpression",
15971
16025
  object,
15972
- property: { kind: "Identifier", name: node.property.name },
15973
- computed: false
16026
+ property: {
16027
+ kind: "Identifier",
16028
+ name: node.property.name,
16029
+ loc: getLoc(node.property)
16030
+ },
16031
+ computed: false,
16032
+ loc: getLoc(node)
15974
16033
  };
15975
16034
  }
15976
16035
 
@@ -18284,7 +18343,8 @@ function lowerNodeWithRegionContext(node, t2, ctx, declaredVars, regionCtx) {
18284
18343
  t2.blockStatement(conseqStmts),
18285
18344
  altStmts ? t2.blockStatement(altStmts) : null
18286
18345
  );
18287
- 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);
18288
18348
  if (shouldWrapEffect) {
18289
18349
  ctx.helpersUsed.add("useEffect");
18290
18350
  ctx.needsCtx = true;
@@ -18512,31 +18572,53 @@ function lowerStructuredNodeForRegion(node, region, t2, ctx, declaredVars, regio
18512
18572
  return stmt ? [stmt] : [];
18513
18573
  }
18514
18574
  case "if": {
18515
- const consequent = lowerStructuredNodeForRegion(
18516
- node.consequent,
18517
- region,
18518
- t2,
18519
- ctx,
18520
- declaredVars,
18521
- regionCtx,
18522
- skipInstructions
18523
- );
18524
- const alternate = node.alternate ? lowerStructuredNodeForRegion(
18525
- node.alternate,
18526
- region,
18527
- t2,
18528
- ctx,
18529
- declaredVars,
18530
- regionCtx,
18531
- skipInstructions
18532
- ) : [];
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) : [];
18533
18608
  if (consequent.length === 0 && alternate.length === 0) return [];
18534
- const ifStmt = t2.ifStatement(
18609
+ const buildIfStmt = (cons, alt) => t2.ifStatement(
18535
18610
  lowerExpressionWithDeSSA(node.test, ctx),
18536
- t2.blockStatement(consequent),
18537
- alternate.length > 0 ? t2.blockStatement(alternate) : null
18611
+ t2.blockStatement(cons),
18612
+ alt.length > 0 ? t2.blockStatement(alt) : null
18538
18613
  );
18539
- 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
+ }
18540
18622
  if (shouldWrapEffect) {
18541
18623
  ctx.helpersUsed.add("useEffect");
18542
18624
  ctx.needsCtx = true;
@@ -18928,11 +19010,17 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
18928
19010
  if (uniqueOutputNames.length === 0) {
18929
19011
  ctx.helpersUsed.add("useEffect");
18930
19012
  ctx.needsCtx = true;
18931
- const effectCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
19013
+ const effectCallArgs = [
18932
19014
  t2.identifier("__fictCtx"),
18933
- t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements)),
18934
- t2.numericLiteral(reserveHookSlot(ctx))
18935
- ]);
19015
+ t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements))
19016
+ ];
19017
+ {
19018
+ const slot = reserveHookSlot(ctx);
19019
+ if (slot >= 0) {
19020
+ effectCallArgs.push(t2.numericLiteral(slot));
19021
+ }
19022
+ }
19023
+ const effectCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), effectCallArgs);
18936
19024
  statements.push(t2.expressionStatement(effectCall));
18937
19025
  } else {
18938
19026
  ctx.helpersUsed.add("useMemo");
@@ -18965,11 +19053,15 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
18965
19053
  };
18966
19054
  const returnObj = t2.objectExpression(uniqueOutputNames.map((name) => buildOutputProperty(name)));
18967
19055
  const memoBody = t2.blockStatement([...bodyStatements, t2.returnStatement(returnObj)]);
18968
- const memoCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), [
19056
+ const slot = reserveHookSlot(ctx);
19057
+ const memoArgs = [
18969
19058
  t2.identifier("__fictCtx"),
18970
- t2.arrowFunctionExpression([], memoBody),
18971
- t2.numericLiteral(reserveHookSlot(ctx))
18972
- ]);
19059
+ t2.arrowFunctionExpression([], memoBody)
19060
+ ];
19061
+ if (slot >= 0) {
19062
+ memoArgs.push(t2.numericLiteral(slot));
19063
+ }
19064
+ const memoCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs);
18973
19065
  const regionVarName = `__region_${region.id}`;
18974
19066
  statements.push(
18975
19067
  t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
@@ -19026,7 +19118,10 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
19026
19118
  t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
19027
19119
  t2.identifier("__fictCtx"),
19028
19120
  t2.arrowFunctionExpression([], effectBody),
19029
- t2.numericLiteral(reserveHookSlot(ctx))
19121
+ (() => {
19122
+ const slot2 = reserveHookSlot(ctx);
19123
+ return slot2 >= 0 ? t2.numericLiteral(slot2) : t2.identifier("undefined");
19124
+ })()
19030
19125
  ])
19031
19126
  )
19032
19127
  );
@@ -19244,11 +19339,15 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
19244
19339
  ctx.helpersUsed.add("useMemo");
19245
19340
  ctx.needsCtx = true;
19246
19341
  const regionVarName = `__region_${region.id}`;
19247
- const memoCall = t2.callExpression(t2.identifier("__fictUseMemo"), [
19342
+ const slotForMemo = reserveHookSlot(ctx);
19343
+ const memoArgs = [
19248
19344
  t2.identifier("__fictCtx"),
19249
- t2.arrowFunctionExpression([], t2.blockStatement(memoBody)),
19250
- t2.numericLiteral(reserveHookSlot(ctx))
19251
- ]);
19345
+ t2.arrowFunctionExpression([], t2.blockStatement(memoBody))
19346
+ ];
19347
+ if (slotForMemo >= 0) {
19348
+ memoArgs.push(t2.numericLiteral(slotForMemo));
19349
+ }
19350
+ const memoCall = t2.callExpression(t2.identifier("__fictUseMemo"), memoArgs);
19252
19351
  statements.push(
19253
19352
  t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
19254
19353
  );
@@ -19270,6 +19369,9 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
19270
19369
  return statements;
19271
19370
  }
19272
19371
  function reserveHookSlot(ctx) {
19372
+ if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
19373
+ return -1;
19374
+ }
19273
19375
  const slot = ctx.nextHookSlot ?? 0;
19274
19376
  ctx.nextHookSlot = slot + 1;
19275
19377
  return slot;
@@ -19340,7 +19442,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19340
19442
  t2.arrowFunctionExpression([], expr)
19341
19443
  ];
19342
19444
  if (inRegionMemo) {
19343
- args.push(t2.numericLiteral(reserveHookSlot(ctx)));
19445
+ const slot = reserveHookSlot(ctx);
19446
+ if (slot >= 0) {
19447
+ args.push(t2.numericLiteral(slot));
19448
+ }
19344
19449
  }
19345
19450
  ctx.helpersUsed.add("useMemo");
19346
19451
  ctx.needsCtx = true;
@@ -19540,7 +19645,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19540
19645
  (dep) => ctx.trackedVars.has(deSSAVarName(dep))
19541
19646
  );
19542
19647
  const usesTracked = expressionUsesTracked(instr.value, ctx);
19543
- const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && (usesTracked || hasTrackedControlDep);
19648
+ const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
19649
+ const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && !inNonReactiveScope && (usesTracked || hasTrackedControlDep);
19544
19650
  if (shouldWrapExpr) {
19545
19651
  ctx.helpersUsed.add("useEffect");
19546
19652
  ctx.needsCtx = true;
@@ -19855,6 +19961,17 @@ function deSSAJSXChild(child, t2) {
19855
19961
  // src/ir/codegen.ts
19856
19962
  var HOOK_SLOT_BASE = 1e3;
19857
19963
  var HOOK_NAME_PREFIX = "use";
19964
+ var cloneLoc = (loc) => loc === void 0 ? void 0 : loc === null ? null : {
19965
+ start: { ...loc.start },
19966
+ end: { ...loc.end },
19967
+ filename: loc.filename,
19968
+ identifierName: loc.identifierName
19969
+ };
19970
+ function setNodeLoc(node, loc) {
19971
+ if (loc === void 0) return node;
19972
+ node.loc = cloneLoc(loc) ?? null;
19973
+ return node;
19974
+ }
19858
19975
  function isHookName(name) {
19859
19976
  return !!name && name.startsWith(HOOK_NAME_PREFIX);
19860
19977
  }
@@ -19888,13 +20005,22 @@ function applyRegionToContext(ctx, region) {
19888
20005
  return prevRegion;
19889
20006
  }
19890
20007
  function reserveHookSlot2(ctx) {
20008
+ if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
20009
+ return -1;
20010
+ }
19891
20011
  const slot = ctx.nextHookSlot ?? HOOK_SLOT_BASE;
19892
20012
  ctx.nextHookSlot = slot + 1;
19893
20013
  return slot;
19894
20014
  }
19895
20015
  function expressionContainsJSX(expr) {
20016
+ if (Array.isArray(expr)) {
20017
+ return expr.some((item) => expressionContainsJSX(item));
20018
+ }
19896
20019
  if (!expr || typeof expr !== "object") return false;
19897
20020
  if (expr.kind === "JSXElement") return true;
20021
+ if (Array.isArray(expr.instructions)) {
20022
+ return expr.instructions.some((i) => expressionContainsJSX(i?.value ?? i));
20023
+ }
19898
20024
  switch (expr.kind) {
19899
20025
  case "CallExpression":
19900
20026
  if (expressionContainsJSX(expr.callee)) return true;
@@ -19907,10 +20033,29 @@ function expressionContainsJSX(expr) {
19907
20033
  return expressionContainsJSX(expr.test) || expressionContainsJSX(expr.consequent) || expressionContainsJSX(expr.alternate);
19908
20034
  case "ArrowFunction":
19909
20035
  return expressionContainsJSX(expr.body);
20036
+ case "FunctionExpression":
20037
+ if (Array.isArray(expr.body)) {
20038
+ return expr.body.some(
20039
+ (block) => block.instructions?.some((i) => expressionContainsJSX(i.value))
20040
+ );
20041
+ }
20042
+ return false;
19910
20043
  default:
19911
20044
  return false;
19912
20045
  }
19913
20046
  }
20047
+ function withNoMemoAndDynamicHooks(ctx, fn) {
20048
+ const prevNoMemo = ctx.noMemo;
20049
+ const prevDynamic = ctx.dynamicHookSlotDepth ?? 0;
20050
+ ctx.noMemo = true;
20051
+ ctx.dynamicHookSlotDepth = prevDynamic + 1;
20052
+ try {
20053
+ return fn();
20054
+ } finally {
20055
+ ctx.noMemo = prevNoMemo;
20056
+ ctx.dynamicHookSlotDepth = prevDynamic;
20057
+ }
20058
+ }
19914
20059
  function functionContainsJSX(fn) {
19915
20060
  for (const block of fn.blocks) {
19916
20061
  for (const instr of block.instructions) {
@@ -21009,18 +21154,25 @@ function lowerTrackedExpression(expr, ctx) {
21009
21154
  }
21010
21155
  function lowerInstruction(instr, ctx) {
21011
21156
  const { t: t2 } = ctx;
21157
+ const applyLoc = (stmt) => {
21158
+ if (!stmt) return stmt;
21159
+ const baseLoc = instr.loc ?? (instr.kind === "Assign" || instr.kind === "Expression" ? instr.value.loc : void 0);
21160
+ return setNodeLoc(stmt, baseLoc);
21161
+ };
21012
21162
  if (instr.kind === "Assign") {
21013
21163
  const baseName2 = deSSAVarName(instr.target.name);
21014
21164
  const isFunctionDecl = instr.value.kind === "FunctionExpression" && (instr.declarationKind === "function" || !instr.declarationKind && instr.value.name === baseName2);
21015
21165
  if (isFunctionDecl) {
21016
21166
  const loweredFn = lowerExpression(instr.value, ctx);
21017
21167
  if (t2.isFunctionExpression(loweredFn)) {
21018
- return t2.functionDeclaration(
21019
- t2.identifier(baseName2),
21020
- loweredFn.params,
21021
- loweredFn.body,
21022
- loweredFn.generator ?? false,
21023
- loweredFn.async ?? false
21168
+ return applyLoc(
21169
+ t2.functionDeclaration(
21170
+ t2.identifier(baseName2),
21171
+ loweredFn.params,
21172
+ loweredFn.body,
21173
+ loweredFn.generator ?? false,
21174
+ loweredFn.async ?? false
21175
+ )
21024
21176
  );
21025
21177
  }
21026
21178
  }
@@ -21035,12 +21187,16 @@ function lowerInstruction(instr, ctx) {
21035
21187
  ctx.memoVars?.add(baseName2);
21036
21188
  }
21037
21189
  if (declKind) {
21038
- return t2.variableDeclaration(declKind, [
21039
- t2.variableDeclarator(t2.identifier(baseName2), hookMember.member)
21040
- ]);
21190
+ return applyLoc(
21191
+ t2.variableDeclaration(declKind, [
21192
+ t2.variableDeclarator(t2.identifier(baseName2), hookMember.member)
21193
+ ])
21194
+ );
21041
21195
  }
21042
- return t2.expressionStatement(
21043
- t2.assignmentExpression("=", t2.identifier(baseName2), hookMember.member)
21196
+ return applyLoc(
21197
+ t2.expressionStatement(
21198
+ t2.assignmentExpression("=", t2.identifier(baseName2), hookMember.member)
21199
+ )
21044
21200
  );
21045
21201
  }
21046
21202
  if (instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && isHookName(instr.value.callee.name)) {
@@ -21054,16 +21210,24 @@ function lowerInstruction(instr, ctx) {
21054
21210
  }
21055
21211
  }
21056
21212
  if (ctx.signalVars?.has(baseName2)) {
21057
- return t2.expressionStatement(
21058
- t2.callExpression(t2.identifier(baseName2), [lowerTrackedExpression(instr.value, ctx)])
21213
+ return applyLoc(
21214
+ t2.expressionStatement(
21215
+ t2.callExpression(t2.identifier(baseName2), [lowerTrackedExpression(instr.value, ctx)])
21216
+ )
21059
21217
  );
21060
21218
  }
21061
- return t2.expressionStatement(
21062
- t2.assignmentExpression("=", t2.identifier(baseName2), lowerTrackedExpression(instr.value, ctx))
21219
+ return applyLoc(
21220
+ t2.expressionStatement(
21221
+ t2.assignmentExpression(
21222
+ "=",
21223
+ t2.identifier(baseName2),
21224
+ lowerTrackedExpression(instr.value, ctx)
21225
+ )
21226
+ )
21063
21227
  );
21064
21228
  }
21065
21229
  if (instr.kind === "Expression") {
21066
- return t2.expressionStatement(lowerTrackedExpression(instr.value, ctx));
21230
+ return applyLoc(t2.expressionStatement(lowerTrackedExpression(instr.value, ctx)));
21067
21231
  }
21068
21232
  if (instr.kind === "Phi") {
21069
21233
  return null;
@@ -21072,6 +21236,9 @@ function lowerInstruction(instr, ctx) {
21072
21236
  }
21073
21237
  function lowerTerminator(block, ctx) {
21074
21238
  const { t: t2 } = ctx;
21239
+ const baseLoc = block.terminator.loc ?? // eslint-disable-next-line @typescript-eslint/no-explicit-any
21240
+ block.terminator.argument?.loc;
21241
+ const applyLoc = (stmts) => stmts.map((stmt) => setNodeLoc(stmt, baseLoc));
21075
21242
  switch (block.terminator.kind) {
21076
21243
  case "Return": {
21077
21244
  const prevRegion = ctx.currentRegion;
@@ -21084,14 +21251,14 @@ function lowerTerminator(block, ctx) {
21084
21251
  }
21085
21252
  ctx.inReturn = false;
21086
21253
  ctx.currentRegion = prevRegion;
21087
- return [t2.returnStatement(retExpr)];
21254
+ return applyLoc([t2.returnStatement(retExpr)]);
21088
21255
  }
21089
21256
  case "Throw":
21090
- return [t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))];
21257
+ return applyLoc([t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))]);
21091
21258
  case "Jump":
21092
- return [t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))];
21259
+ return applyLoc([t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))]);
21093
21260
  case "Branch":
21094
- return [
21261
+ return applyLoc([
21095
21262
  t2.ifStatement(
21096
21263
  lowerTrackedExpression(block.terminator.test, ctx),
21097
21264
  t2.blockStatement([
@@ -21101,9 +21268,9 @@ function lowerTerminator(block, ctx) {
21101
21268
  t2.expressionStatement(t2.stringLiteral(`goto ${block.terminator.alternate}`))
21102
21269
  ])
21103
21270
  )
21104
- ];
21271
+ ]);
21105
21272
  case "Switch":
21106
- return [
21273
+ return applyLoc([
21107
21274
  t2.switchStatement(
21108
21275
  lowerTrackedExpression(block.terminator.discriminant, ctx),
21109
21276
  block.terminator.cases.map(
@@ -21112,30 +21279,30 @@ function lowerTerminator(block, ctx) {
21112
21279
  ])
21113
21280
  )
21114
21281
  )
21115
- ];
21282
+ ]);
21116
21283
  case "ForOf": {
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.forOfStatement(
21122
21289
  t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
21123
21290
  lowerExpression(term.iterable, ctx),
21124
21291
  t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
21125
21292
  )
21126
- ];
21293
+ ]);
21127
21294
  }
21128
21295
  case "ForIn": {
21129
21296
  const term = block.terminator;
21130
21297
  const varKind = term.variableKind ?? "const";
21131
21298
  const leftPattern = term.pattern ? term.pattern : t2.identifier(term.variable);
21132
- return [
21299
+ return applyLoc([
21133
21300
  t2.forInStatement(
21134
21301
  t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
21135
21302
  lowerExpression(term.object, ctx),
21136
21303
  t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
21137
21304
  )
21138
- ];
21305
+ ]);
21139
21306
  }
21140
21307
  case "Try": {
21141
21308
  const term = block.terminator;
@@ -21151,20 +21318,20 @@ function lowerTerminator(block, ctx) {
21151
21318
  const finallyBlock = term.finallyBlock !== void 0 ? t2.blockStatement([
21152
21319
  t2.expressionStatement(t2.stringLiteral(`finally ${term.finallyBlock}`))
21153
21320
  ]) : null;
21154
- return [t2.tryStatement(tryBlock, catchClause, finallyBlock)];
21321
+ return applyLoc([t2.tryStatement(tryBlock, catchClause, finallyBlock)]);
21155
21322
  }
21156
21323
  case "Unreachable":
21157
- return [];
21324
+ return applyLoc([]);
21158
21325
  case "Break":
21159
- return [
21326
+ return applyLoc([
21160
21327
  t2.breakStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
21161
- ];
21328
+ ]);
21162
21329
  case "Continue":
21163
- return [
21330
+ return applyLoc([
21164
21331
  t2.continueStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
21165
- ];
21332
+ ]);
21166
21333
  default:
21167
- return [];
21334
+ return applyLoc([]);
21168
21335
  }
21169
21336
  }
21170
21337
  function attachHelperImports(ctx, body, t2) {
@@ -21303,12 +21470,12 @@ function lowerExpression(expr, ctx, isAssigned = false) {
21303
21470
  }
21304
21471
  ctx.expressionDepth = depth;
21305
21472
  try {
21306
- return lowerExpressionImpl(expr, ctx, isAssigned);
21473
+ return setNodeLoc(lowerExpressionImpl(expr, ctx, isAssigned), expr.loc);
21307
21474
  } finally {
21308
21475
  ctx.expressionDepth = depth - 1;
21309
21476
  }
21310
21477
  }
21311
- function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21478
+ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21312
21479
  const { t: t2 } = ctx;
21313
21480
  const mapParams = (params) => params.map((p) => t2.identifier(deSSAVarName(p.name)));
21314
21481
  const withFunctionScope = (paramNames, fn) => {
@@ -21370,11 +21537,7 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21370
21537
  };
21371
21538
  const declared = new Set(paramIds.map((p) => p.name));
21372
21539
  return lowerStructuredNodeWithoutRegions(structured, t2, ctx, declared);
21373
- } catch (e) {
21374
- console.log(
21375
- "[DEBUG] Structurization failed, falling back to lowerBlocksToStatements via lowerInstruction",
21376
- e
21377
- );
21540
+ } catch {
21378
21541
  return lowerBlocksToStatements(blocks);
21379
21542
  }
21380
21543
  };
@@ -21438,14 +21601,22 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21438
21601
  const calleeIsMemoAccessor = !!calleeName && ctx.memoVars?.has(calleeName);
21439
21602
  const calleeIsSignalLike = !!calleeName && (ctx.signalVars?.has(calleeName) || ctx.storeVars?.has(calleeName));
21440
21603
  if (calleeIsMemoAccessor && !calleeIsSignalLike && expr.arguments.length > 0) {
21441
- const loweredArgs = expr.arguments.map((a) => lowerExpression(a, ctx));
21442
- return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs);
21604
+ const loweredArgs2 = expr.arguments.map((a) => lowerExpression(a, ctx));
21605
+ return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs2);
21443
21606
  }
21444
21607
  const lowerCallee = () => isIIFE ? withNonReactiveScope(ctx, () => lowerExpression(expr.callee, ctx)) : lowerExpression(expr.callee, ctx);
21445
- return t2.callExpression(
21446
- lowerCallee(),
21447
- expr.arguments.map((a) => lowerExpression(a, ctx))
21448
- );
21608
+ const isIteratingMethod = expr.callee.kind === "MemberExpression" && (expr.callee.property.kind === "Identifier" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
21609
+ expr.callee.property.name
21610
+ ) || expr.callee.property.kind === "Literal" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
21611
+ String(expr.callee.property.value)
21612
+ ));
21613
+ const loweredArgs = expr.arguments.map((a, idx) => {
21614
+ if (idx === 0 && isIteratingMethod && (a.kind === "ArrowFunction" || a.kind === "FunctionExpression")) {
21615
+ return withNoMemoAndDynamicHooks(ctx, () => lowerExpression(a, ctx));
21616
+ }
21617
+ return lowerExpression(a, ctx);
21618
+ });
21619
+ return t2.callExpression(lowerCallee(), loweredArgs);
21449
21620
  }
21450
21621
  case "MemberExpression":
21451
21622
  if (matchesListKeyPattern(expr, ctx)) {
@@ -21545,12 +21716,10 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21545
21716
  case "ArrowFunction": {
21546
21717
  const paramIds = mapParams(expr.params);
21547
21718
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
21548
- return withFunctionScope(shadowed, () => {
21549
- if (isAssigned) {
21550
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) + 1;
21551
- }
21552
- let fn;
21553
- try {
21719
+ return withNonReactiveScope(
21720
+ ctx,
21721
+ () => withFunctionScope(shadowed, () => {
21722
+ let fn;
21554
21723
  if (expr.isExpression && !Array.isArray(expr.body)) {
21555
21724
  const { result: bodyExpr, cacheDeclarations } = withGetterCache(
21556
21725
  ctx,
@@ -21578,12 +21747,8 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
21578
21747
  }
21579
21748
  fn.async = expr.isAsync ?? false;
21580
21749
  return fn;
21581
- } finally {
21582
- if (isAssigned) {
21583
- ctx.nonReactiveScopeDepth = (ctx.nonReactiveScopeDepth ?? 0) - 1;
21584
- }
21585
- }
21586
- });
21750
+ })
21751
+ );
21587
21752
  }
21588
21753
  case "FunctionExpression": {
21589
21754
  const paramIds = mapParams(expr.params);
@@ -22302,15 +22467,6 @@ function isStaticValue(expr) {
22302
22467
  if (!expr) return false;
22303
22468
  return expr.kind === "Literal";
22304
22469
  }
22305
- function isComponentLikeCallee(expr) {
22306
- if (expr.kind === "Identifier") {
22307
- return expr.name[0] === expr.name[0]?.toUpperCase();
22308
- }
22309
- if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
22310
- return isComponentLikeCallee(expr.object);
22311
- }
22312
- return false;
22313
- }
22314
22470
  function isLikelyTextExpression(expr, ctx) {
22315
22471
  let ok = true;
22316
22472
  const isReactiveIdentifier = (name) => {
@@ -22339,15 +22495,9 @@ function isLikelyTextExpression(expr, ctx) {
22339
22495
  ok = false;
22340
22496
  return;
22341
22497
  case "CallExpression":
22342
- case "OptionalCallExpression": {
22343
- if (isComponentLikeCallee(node.callee)) {
22344
- ok = false;
22345
- return;
22346
- }
22347
- visit(node.callee, true);
22348
- node.arguments.forEach((arg) => visit(arg));
22498
+ case "OptionalCallExpression":
22499
+ ok = false;
22349
22500
  return;
22350
- }
22351
22501
  case "MemberExpression":
22352
22502
  case "OptionalMemberExpression":
22353
22503
  visit(node.object, true);
@@ -22779,16 +22929,28 @@ function lowerIntrinsicElement(jsx, ctx) {
22779
22929
  t2.expressionStatement(lowerDomExpression(binding.expr, ctx, containingRegion))
22780
22930
  );
22781
22931
  } else if (binding.type === "text" && binding.expr) {
22782
- ctx.helpersUsed.add("bindText");
22783
22932
  const valueExpr = lowerDomExpression(binding.expr, ctx, containingRegion);
22784
- statements.push(
22785
- t2.expressionStatement(
22786
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22787
- targetId,
22788
- t2.arrowFunctionExpression([], valueExpr)
22789
- ])
22790
- )
22791
- );
22933
+ if (isExpressionReactive(binding.expr, ctx)) {
22934
+ ctx.helpersUsed.add("bindText");
22935
+ statements.push(
22936
+ t2.expressionStatement(
22937
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.bindText), [
22938
+ targetId,
22939
+ t2.arrowFunctionExpression([], valueExpr)
22940
+ ])
22941
+ )
22942
+ );
22943
+ } else {
22944
+ statements.push(
22945
+ t2.expressionStatement(
22946
+ t2.assignmentExpression(
22947
+ "=",
22948
+ t2.memberExpression(targetId, t2.identifier("data")),
22949
+ t2.callExpression(t2.identifier("String"), [valueExpr])
22950
+ )
22951
+ )
22952
+ );
22953
+ }
22792
22954
  } else if (binding.type === "child" && binding.expr) {
22793
22955
  emitHIRChildBinding(targetId, binding.expr, statements, ctx, containingRegion);
22794
22956
  }
@@ -22802,7 +22964,12 @@ function lowerIntrinsicElement(jsx, ctx) {
22802
22964
  t2.arrowFunctionExpression([], body)
22803
22965
  ];
22804
22966
  if (ctx.isComponentFn) {
22805
- memoArgs.push(t2.numericLiteral(reserveHookSlot2(ctx)));
22967
+ {
22968
+ const slot = reserveHookSlot2(ctx);
22969
+ if (slot >= 0) {
22970
+ memoArgs.push(t2.numericLiteral(slot));
22971
+ }
22972
+ }
22806
22973
  }
22807
22974
  return t2.callExpression(t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs), []);
22808
22975
  }
@@ -23097,8 +23264,13 @@ function getTrackedCallIdentifier(expr, ctx, itemParamName) {
23097
23264
  }
23098
23265
  return null;
23099
23266
  }
23100
- function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23267
+ function rewriteSelectorExpression(expr, itemParamName, keyParamName, getSelectorId, ctx) {
23101
23268
  const { t: t2 } = ctx;
23269
+ const usesParamIdentifier = (e) => {
23270
+ if (expressionUsesIdentifier(e, itemParamName, t2)) return true;
23271
+ if (keyParamName && expressionUsesIdentifier(e, keyParamName, t2)) return true;
23272
+ return false;
23273
+ };
23102
23274
  if (t2.isBinaryExpression(expr) && (expr.operator === "===" || expr.operator === "==")) {
23103
23275
  const leftTracked = getTrackedCallIdentifier(
23104
23276
  expr.left,
@@ -23110,7 +23282,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23110
23282
  ctx,
23111
23283
  itemParamName
23112
23284
  );
23113
- if (leftTracked && expressionUsesIdentifier(expr.right, itemParamName, t2)) {
23285
+ if (leftTracked && usesParamIdentifier(expr.right)) {
23114
23286
  return {
23115
23287
  expr: t2.callExpression(getSelectorId(leftTracked), [
23116
23288
  expr.right
@@ -23118,7 +23290,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23118
23290
  changed: true
23119
23291
  };
23120
23292
  }
23121
- if (rightTracked && expressionUsesIdentifier(expr.left, itemParamName, t2)) {
23293
+ if (rightTracked && usesParamIdentifier(expr.left)) {
23122
23294
  return {
23123
23295
  expr: t2.callExpression(getSelectorId(rightTracked), [
23124
23296
  expr.left
@@ -23129,7 +23301,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23129
23301
  }
23130
23302
  let changed = false;
23131
23303
  const rewrite = (node) => {
23132
- const result = rewriteSelectorExpression(node, itemParamName, getSelectorId, ctx);
23304
+ const result = rewriteSelectorExpression(node, itemParamName, keyParamName, getSelectorId, ctx);
23133
23305
  if (result.changed) changed = true;
23134
23306
  return result.expr;
23135
23307
  };
@@ -23190,7 +23362,7 @@ function rewriteSelectorExpression(expr, itemParamName, getSelectorId, ctx) {
23190
23362
  }
23191
23363
  return { expr, changed };
23192
23364
  }
23193
- function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23365
+ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statements, ctx) {
23194
23366
  const { t: t2 } = ctx;
23195
23367
  if (!itemParamName) return;
23196
23368
  if (!t2.isArrowFunctionExpression(callbackExpr) && !t2.isFunctionExpression(callbackExpr)) return;
@@ -23206,7 +23378,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23206
23378
  if (t2.isBlockStatement(fn.body)) {
23207
23379
  for (const stmt of fn.body.body) {
23208
23380
  if (t2.isReturnStatement(stmt) && stmt.argument && t2.isExpression(stmt.argument)) {
23209
- const result = rewriteSelectorExpression(stmt.argument, itemParamName, getSelectorId, ctx);
23381
+ const result = rewriteSelectorExpression(
23382
+ stmt.argument,
23383
+ itemParamName,
23384
+ keyParamName,
23385
+ getSelectorId,
23386
+ ctx
23387
+ );
23210
23388
  if (result.changed) {
23211
23389
  stmt.argument = result.expr;
23212
23390
  }
@@ -23215,7 +23393,13 @@ function applySelectorHoist(callbackExpr, itemParamName, statements, ctx) {
23215
23393
  return;
23216
23394
  }
23217
23395
  if (t2.isExpression(fn.body)) {
23218
- const result = rewriteSelectorExpression(fn.body, itemParamName, getSelectorId, ctx);
23396
+ const result = rewriteSelectorExpression(
23397
+ fn.body,
23398
+ itemParamName,
23399
+ keyParamName,
23400
+ getSelectorId,
23401
+ ctx
23402
+ );
23219
23403
  if (result.changed) {
23220
23404
  fn.body = result.expr;
23221
23405
  }
@@ -23357,12 +23541,16 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23357
23541
  const hoistedStatements = ctx.hoistedTemplateStatements;
23358
23542
  ctx.hoistedTemplates = prevHoistedTemplates;
23359
23543
  ctx.hoistedTemplateStatements = prevHoistedTemplateStatements;
23360
- if (isKeyed && (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr))) {
23361
- const firstParam = callbackExpr.params[0];
23544
+ if (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) {
23545
+ const [firstParam, secondParam] = callbackExpr.params;
23546
+ const overrides = {};
23362
23547
  if (t2.isIdentifier(firstParam)) {
23363
- const overrides = {
23364
- [firstParam.name]: () => t2.callExpression(t2.identifier(firstParam.name), [])
23365
- };
23548
+ overrides[firstParam.name] = () => t2.callExpression(t2.identifier(firstParam.name), []);
23549
+ }
23550
+ if (t2.isIdentifier(secondParam)) {
23551
+ overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
23552
+ }
23553
+ if (Object.keys(overrides).length > 0) {
23366
23554
  if (t2.isBlockStatement(callbackExpr.body)) {
23367
23555
  replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
23368
23556
  } else {
@@ -23375,7 +23563,14 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23375
23563
  const listId = genTemp(ctx, "list");
23376
23564
  if (isKeyed) {
23377
23565
  const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : null : null;
23378
- applySelectorHoist(callbackExpr, itemParamName, statements, ctx);
23566
+ const keyParamName = ctx.listKeyParamName ?? null;
23567
+ applySelectorHoist(
23568
+ callbackExpr,
23569
+ itemParamName,
23570
+ keyParamName,
23571
+ statements,
23572
+ ctx
23573
+ );
23379
23574
  }
23380
23575
  if (isKeyed && keyExpr) {
23381
23576
  let keyExprAst = lowerExpression(keyExpr, ctx);
@@ -24256,10 +24451,9 @@ function lowerFunctionWithRegions(fn, ctx) {
24256
24451
  }
24257
24452
  }
24258
24453
  const params = finalParams;
24259
- const funcDecl = t2.functionDeclaration(
24260
- t2.identifier(fn.name ?? "fn"),
24261
- params,
24262
- t2.blockStatement(statements)
24454
+ const funcDecl = setNodeLoc(
24455
+ t2.functionDeclaration(t2.identifier(fn.name ?? "fn"), params, t2.blockStatement(statements)),
24456
+ fn.loc
24263
24457
  );
24264
24458
  ctx.needsCtx = prevNeedsCtx;
24265
24459
  ctx.shadowedNames = prevShadowed;
@@ -24348,10 +24542,44 @@ function isInsideNestedFunction(path) {
24348
24542
  function isInsideJSX(path) {
24349
24543
  return !!path.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
24350
24544
  }
24351
- function emitWarning(node, code, message, options, fileName) {
24352
- if (!options.onWarn) return;
24545
+ function parseSuppressionCodes(raw) {
24546
+ if (!raw) return void 0;
24547
+ const codes = raw.split(/[,\s]+/).map((c) => c.trim()).filter(Boolean);
24548
+ return codes.length > 0 ? new Set(codes) : void 0;
24549
+ }
24550
+ function parseSuppressions(comments) {
24551
+ if (!comments) return [];
24552
+ const suppressions = [];
24553
+ for (const comment of comments) {
24554
+ const match = comment.value.match(/fict-ignore(-next-line)?(?:\s+(.+))?/i);
24555
+ if (!match || !comment.loc) continue;
24556
+ suppressions.push({
24557
+ line: comment.loc.start.line,
24558
+ nextLine: !!match[1],
24559
+ codes: parseSuppressionCodes(match[2])
24560
+ });
24561
+ }
24562
+ return suppressions;
24563
+ }
24564
+ function shouldSuppressWarning(suppressions, code, line) {
24565
+ return suppressions.some((entry) => {
24566
+ const targetLine = entry.nextLine ? entry.line + 1 : entry.line;
24567
+ if (targetLine !== line) return false;
24568
+ if (!entry.codes || entry.codes.size === 0) return true;
24569
+ return entry.codes.has(code);
24570
+ });
24571
+ }
24572
+ function createWarningDispatcher(onWarn, suppressions) {
24573
+ if (!onWarn) return () => {
24574
+ };
24575
+ return (warning) => {
24576
+ if (shouldSuppressWarning(suppressions, warning.code, warning.line)) return;
24577
+ onWarn(warning);
24578
+ };
24579
+ }
24580
+ function emitWarning(node, code, message, warn, fileName) {
24353
24581
  const loc = node.loc?.start;
24354
- options.onWarn({
24582
+ warn({
24355
24583
  code,
24356
24584
  message,
24357
24585
  fileName,
@@ -24439,8 +24667,7 @@ function isDynamicPropertyAccess(node, t2) {
24439
24667
  if (!node.computed) return false;
24440
24668
  return !(t2.isStringLiteral(node.property) || t2.isNumericLiteral(node.property));
24441
24669
  }
24442
- function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24443
- const fileName = programPath.hub?.file?.opts?.filename || "<unknown>";
24670
+ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t2) {
24444
24671
  const isStateRoot = (expr) => {
24445
24672
  const root = getRootIdentifier(expr, t2);
24446
24673
  return !!(root && stateVars.has(root.name));
@@ -24456,7 +24683,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24456
24683
  path.node,
24457
24684
  "FICT-M",
24458
24685
  "Direct mutation of nested property detected; use immutable update or $store helpers",
24459
- options,
24686
+ warn,
24460
24687
  fileName
24461
24688
  );
24462
24689
  if (isDynamicPropertyAccess(left, t2)) {
@@ -24464,7 +24691,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24464
24691
  path.node,
24465
24692
  "FICT-H",
24466
24693
  "Dynamic property access widens dependency tracking",
24467
- options,
24694
+ warn,
24468
24695
  fileName
24469
24696
  );
24470
24697
  }
@@ -24479,7 +24706,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24479
24706
  path.node,
24480
24707
  "FICT-M",
24481
24708
  "Direct mutation of nested property detected; use immutable update or $store helpers",
24482
- options,
24709
+ warn,
24483
24710
  fileName
24484
24711
  );
24485
24712
  if (isDynamicPropertyAccess(arg, t2)) {
@@ -24487,7 +24714,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24487
24714
  path.node,
24488
24715
  "FICT-H",
24489
24716
  "Dynamic property access widens dependency tracking",
24490
- options,
24717
+ warn,
24491
24718
  fileName
24492
24719
  );
24493
24720
  }
@@ -24503,7 +24730,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24503
24730
  path.node,
24504
24731
  "FICT-H",
24505
24732
  "Dynamic property access widens dependency tracking",
24506
- options,
24733
+ warn,
24507
24734
  fileName
24508
24735
  );
24509
24736
  }
@@ -24532,7 +24759,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24532
24759
  path.node,
24533
24760
  "FICT-R005",
24534
24761
  `Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
24535
- options,
24762
+ warn,
24536
24763
  fileName
24537
24764
  );
24538
24765
  }
@@ -24563,7 +24790,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24563
24790
  path.node,
24564
24791
  "FICT-E001",
24565
24792
  "Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
24566
- options,
24793
+ warn,
24567
24794
  fileName
24568
24795
  );
24569
24796
  }
@@ -24589,7 +24816,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24589
24816
  arg,
24590
24817
  "FICT-H",
24591
24818
  "State value passed to unknown function (black box); dependency tracking may be imprecise",
24592
- options,
24819
+ warn,
24593
24820
  fileName
24594
24821
  );
24595
24822
  break;
@@ -24605,7 +24832,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
24605
24832
  path.node,
24606
24833
  "FICT-H",
24607
24834
  "Dynamic property access widens dependency tracking",
24608
- options,
24835
+ warn,
24609
24836
  fileName
24610
24837
  );
24611
24838
  }
@@ -24655,6 +24882,10 @@ function createHIREntrypointVisitor(t2, options) {
24655
24882
  Program: {
24656
24883
  exit(path) {
24657
24884
  const fileName = path.hub?.file?.opts?.filename || "<unknown>";
24885
+ const comments = path.hub?.file?.ast?.comments || [];
24886
+ const suppressions = parseSuppressions(comments);
24887
+ const warn = createWarningDispatcher(options.onWarn, suppressions);
24888
+ const optionsWithWarnings = { ...options, onWarn: warn };
24658
24889
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
24659
24890
  const getFunctionName = (fnPath) => {
24660
24891
  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;
@@ -24673,14 +24904,75 @@ function createHIREntrypointVisitor(t2, options) {
24673
24904
  return name && isComponentName(name) || isHookName2(name) || functionHasJSX(fnPath) || functionUsesStateLike(fnPath, t2);
24674
24905
  };
24675
24906
  const memoHasSideEffects = (fn) => {
24907
+ const pureCalls = new Set(
24908
+ Array.from(SAFE_FUNCTIONS).filter(
24909
+ (name) => !name.startsWith("console.") && name !== "Math.random"
24910
+ )
24911
+ );
24912
+ const effectfulCalls = /* @__PURE__ */ new Set([
24913
+ "$effect",
24914
+ "render",
24915
+ "fetch",
24916
+ "setTimeout",
24917
+ "setInterval",
24918
+ "clearTimeout",
24919
+ "clearInterval",
24920
+ "requestAnimationFrame",
24921
+ "cancelAnimationFrame"
24922
+ ]);
24923
+ const getCalleeName = (callee) => {
24924
+ if (t2.isIdentifier(callee)) return callee.name;
24925
+ if (t2.isMemberExpression(callee) && !callee.computed && t2.isIdentifier(callee.property) && t2.isIdentifier(callee.object)) {
24926
+ return `${callee.object.name}.${callee.property.name}`;
24927
+ }
24928
+ return null;
24929
+ };
24930
+ const mutatingMemberProps = /* @__PURE__ */ new Set([
24931
+ "push",
24932
+ "pop",
24933
+ "splice",
24934
+ "shift",
24935
+ "unshift",
24936
+ "sort",
24937
+ "reverse",
24938
+ "set",
24939
+ "add",
24940
+ "delete",
24941
+ "append",
24942
+ "appendChild",
24943
+ "remove",
24944
+ "removeChild",
24945
+ "setAttribute",
24946
+ "dispatchEvent",
24947
+ "replaceChildren",
24948
+ "replaceWith"
24949
+ ]);
24950
+ const isEffectfulCall = (node) => {
24951
+ const name = getCalleeName(node.callee);
24952
+ if (!name) return true;
24953
+ if (pureCalls.has(name)) return false;
24954
+ if (effectfulCalls.has(name)) return true;
24955
+ if (name.startsWith("console.") || name.startsWith("document.") || name.startsWith("window.")) {
24956
+ return true;
24957
+ }
24958
+ if (t2.isMemberExpression(node.callee) && !node.callee.computed && t2.isIdentifier(node.callee.property)) {
24959
+ const prop = node.callee.property.name;
24960
+ if (mutatingMemberProps.has(prop)) return true;
24961
+ if (t2.isIdentifier(node.callee.object) && (node.callee.object.name === "document" || node.callee.object.name === "window")) {
24962
+ return true;
24963
+ }
24964
+ }
24965
+ return false;
24966
+ };
24676
24967
  const checkNode = (node) => {
24677
24968
  if (!node) return false;
24678
24969
  if (t2.isAssignmentExpression(node) || t2.isUpdateExpression(node) || t2.isThrowStatement(node) || t2.isNewExpression(node)) {
24679
24970
  return true;
24680
24971
  }
24681
- if (t2.isCallExpression(node) && (t2.isIdentifier(node.callee) && node.callee.name === "$effect" || t2.isIdentifier(node.callee) && node.callee.name === "render")) {
24972
+ if (t2.isCallExpression(node) && isEffectfulCall(node)) {
24682
24973
  return true;
24683
24974
  }
24975
+ if (t2.isAwaitExpression(node)) return true;
24684
24976
  if (t2.isExpressionStatement(node)) return checkNode(node.expression);
24685
24977
  if (t2.isBlockStatement(node)) return node.body.some((stmt) => checkNode(stmt));
24686
24978
  if (t2.isReturnStatement(node)) return checkNode(node.argument);
@@ -24704,7 +24996,7 @@ function createHIREntrypointVisitor(t2, options) {
24704
24996
  fnPath.node,
24705
24997
  "FICT-C004",
24706
24998
  "Component has no return statement and will render nothing.",
24707
- options,
24999
+ warn,
24708
25000
  fileName
24709
25001
  );
24710
25002
  },
@@ -24722,7 +25014,7 @@ function createHIREntrypointVisitor(t2, options) {
24722
25014
  init,
24723
25015
  "FICT-C004",
24724
25016
  "Component has no return statement and will render nothing.",
24725
- options,
25017
+ warn,
24726
25018
  fileName
24727
25019
  );
24728
25020
  }
@@ -24772,7 +25064,7 @@ function createHIREntrypointVisitor(t2, options) {
24772
25064
  }
24773
25065
  }
24774
25066
  if (hasKey || hasUnknownSpread) return;
24775
- options.onWarn?.({
25067
+ warn({
24776
25068
  code: "FICT-J002",
24777
25069
  message: "Missing key prop in list rendering.",
24778
25070
  fileName,
@@ -24843,7 +25135,7 @@ function createHIREntrypointVisitor(t2, options) {
24843
25135
  fnPath.node,
24844
25136
  "FICT-C003",
24845
25137
  "Components should not be defined inside other components. Move this definition to module scope to preserve identity and performance.",
24846
- options,
25138
+ warn,
24847
25139
  fileName
24848
25140
  );
24849
25141
  },
@@ -24888,7 +25180,7 @@ function createHIREntrypointVisitor(t2, options) {
24888
25180
  callPath.node,
24889
25181
  "FICT-R004",
24890
25182
  "Reactive creation inside non-JSX control flow will not auto-dispose; wrap it in createScope/runInScope or move it into JSX-managed regions.",
24891
- options,
25183
+ warn,
24892
25184
  fileName
24893
25185
  );
24894
25186
  }
@@ -24923,7 +25215,7 @@ function createHIREntrypointVisitor(t2, options) {
24923
25215
  callPath.node.arguments.forEach((arg) => {
24924
25216
  if (t2.isIdentifier(arg) && stateVars.has(arg.name) && (!calleeId || !allowedStateCallees.has(calleeId))) {
24925
25217
  const loc = arg.loc?.start ?? callPath.node.loc?.start;
24926
- options.onWarn?.({
25218
+ warn({
24927
25219
  code: "FICT-S002",
24928
25220
  message: "State variable is passed as an argument; this passes a value snapshot and may escape component scope.",
24929
25221
  fileName,
@@ -24936,7 +25228,7 @@ function createHIREntrypointVisitor(t2, options) {
24936
25228
  const firstArg = callPath.node.arguments[0];
24937
25229
  if (firstArg && (t2.isArrowFunctionExpression(firstArg) || t2.isFunctionExpression(firstArg)) && memoHasSideEffects(firstArg)) {
24938
25230
  const loc = firstArg.loc?.start ?? callPath.node.loc?.start;
24939
- options.onWarn?.({
25231
+ warn({
24940
25232
  code: "FICT-M003",
24941
25233
  message: "Memo should not contain side effects.",
24942
25234
  fileName,
@@ -25041,10 +25333,10 @@ function createHIREntrypointVisitor(t2, options) {
25041
25333
  }
25042
25334
  });
25043
25335
  }
25044
- runWarningPass(path, stateVars, derivedVars, options, t2);
25336
+ runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25045
25337
  const fileAst = t2.file(path.node);
25046
25338
  const hir = buildHIR(fileAst);
25047
- const lowered = lowerHIRWithRegions(hir, t2, options);
25339
+ const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
25048
25340
  path.node.body = lowered.program.body;
25049
25341
  path.node.directives = lowered.program.directives;
25050
25342
  if (!process.env.FICT_SKIP_SCOPE_CRAWL) {