@fictjs/compiler 0.0.11 → 0.0.13

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 +246 -115
  2. package/dist/index.js +246 -115
  3. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -14143,7 +14143,6 @@ var RUNTIME_HELPERS = {
14143
14143
  runInScope: "runInScope",
14144
14144
  createElement: "createElement",
14145
14145
  conditional: "createConditional",
14146
- list: "createList",
14147
14146
  keyedList: "createKeyedList",
14148
14147
  insert: "insert",
14149
14148
  onDestroy: "onDestroy",
@@ -14156,11 +14155,6 @@ var RUNTIME_HELPERS = {
14156
14155
  callEventHandler: "callEventHandler",
14157
14156
  bindRef: "bindRef",
14158
14157
  toNodeArray: "toNodeArray",
14159
- createKeyedListContainer: "createKeyedListContainer",
14160
- createKeyedBlock: "createKeyedBlock",
14161
- moveMarkerBlock: "moveMarkerBlock",
14162
- destroyMarkerBlock: "destroyMarkerBlock",
14163
- getFirstNodeAfter: "getFirstNodeAfter",
14164
14158
  template: "template",
14165
14159
  delegateEvents: "delegateEvents"
14166
14160
  };
@@ -14184,7 +14178,6 @@ var RUNTIME_ALIASES = {
14184
14178
  runInScope: "runInScope",
14185
14179
  createElement: "createElement",
14186
14180
  conditional: "createConditional",
14187
- list: "createList",
14188
14181
  keyedList: "createKeyedList",
14189
14182
  insert: "insert",
14190
14183
  onDestroy: "onDestroy",
@@ -14197,11 +14190,6 @@ var RUNTIME_ALIASES = {
14197
14190
  callEventHandler: "callEventHandler",
14198
14191
  bindRef: "bindRef",
14199
14192
  toNodeArray: "toNodeArray",
14200
- createKeyedListContainer: "createKeyedListContainer",
14201
- createKeyedBlock: "createKeyedBlock",
14202
- moveMarkerBlock: "moveMarkerBlock",
14203
- destroyMarkerBlock: "destroyMarkerBlock",
14204
- getFirstNodeAfter: "getFirstNodeAfter",
14205
14193
  template: "template",
14206
14194
  delegateEvents: "delegateEvents"
14207
14195
  };
@@ -14318,9 +14306,13 @@ var HIRError = class extends Error {
14318
14306
  }
14319
14307
  };
14320
14308
  var SSA_PATTERN = /\$\$ssa\d+$/;
14309
+ var GENERATED_SSA_NAMES = /* @__PURE__ */ new Set();
14321
14310
  function getSSABaseName(name) {
14322
14311
  if (name.startsWith("__")) return name;
14323
- return name.replace(SSA_PATTERN, "");
14312
+ if (GENERATED_SSA_NAMES.has(name)) {
14313
+ return name.replace(SSA_PATTERN, "");
14314
+ }
14315
+ return SSA_PATTERN.test(name) ? name : name;
14324
14316
  }
14325
14317
  function extractDependencyPath(expr) {
14326
14318
  if (expr.kind === "Identifier") {
@@ -16050,38 +16042,6 @@ function debugEnabled(flag) {
16050
16042
  return parts.includes(normalized) || parts.includes("all");
16051
16043
  }
16052
16044
 
16053
- // src/utils.ts
16054
- function isStateCall(node, t2) {
16055
- return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
16056
- }
16057
- function isEffectCall(node, t2) {
16058
- return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
16059
- }
16060
- function getRootIdentifier(expr, t2) {
16061
- if (t2.isIdentifier(expr)) {
16062
- return expr;
16063
- }
16064
- if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
16065
- return getRootIdentifier(expr.object, t2);
16066
- }
16067
- if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
16068
- return getRootIdentifier(expr.object, t2);
16069
- }
16070
- if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
16071
- return getRootIdentifier(expr.callee, t2);
16072
- }
16073
- if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
16074
- return getRootIdentifier(expr.callee, t2);
16075
- }
16076
- if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
16077
- return getRootIdentifier(expr.expression, t2);
16078
- }
16079
- if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
16080
- return getRootIdentifier(expr.expression, t2);
16081
- }
16082
- return null;
16083
- }
16084
-
16085
16045
  // src/fine-grained-dom.ts
16086
16046
  function normalizeDependencyKey(name) {
16087
16047
  return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
@@ -16090,35 +16050,113 @@ function applyRegionMetadata(state, options) {
16090
16050
  if (!options.region) return;
16091
16051
  const region = options.region;
16092
16052
  state.regionMetadata = region;
16093
- if (region.dependencies.size > 0) {
16094
- state.identifierOverrides = state.identifierOverrides ?? {};
16095
- const dependencyGetter = options.dependencyGetter ?? null;
16096
- if (!dependencyGetter) {
16097
- return;
16098
- }
16099
- for (const dep of region.dependencies) {
16100
- const key = normalizeDependencyKey(dep);
16101
- state.identifierOverrides[key] = () => dependencyGetter(dep);
16102
- const base = key.split(".")[0];
16103
- if (base && !state.identifierOverrides[base]) {
16104
- state.identifierOverrides[base] = () => dependencyGetter(base);
16105
- }
16053
+ if (region.dependencies.size === 0) return;
16054
+ const dependencyGetter = options.dependencyGetter;
16055
+ if (!dependencyGetter) return;
16056
+ state.identifierOverrides = state.identifierOverrides ?? {};
16057
+ for (const dep of region.dependencies) {
16058
+ const key = normalizeDependencyKey(dep);
16059
+ state.identifierOverrides[key] = () => dependencyGetter(dep);
16060
+ const base = key.split(".")[0];
16061
+ if (base && !state.identifierOverrides[base]) {
16062
+ state.identifierOverrides[base] = () => dependencyGetter(base);
16106
16063
  }
16107
16064
  }
16108
16065
  }
16109
16066
  function shouldMemoizeRegion(region) {
16110
- if (region.dependencies.size > 0) {
16111
- return true;
16112
- }
16113
- if (region.hasControlFlow) {
16114
- return true;
16115
- }
16116
- if (region.hasReactiveWrites) {
16117
- return true;
16118
- }
16067
+ if (region.dependencies.size > 0) return true;
16068
+ if (region.hasControlFlow) return true;
16069
+ if (region.hasReactiveWrites) return true;
16119
16070
  return false;
16120
16071
  }
16121
16072
 
16073
+ // src/validation.ts
16074
+ var DiagnosticMessages = {
16075
+ ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
16076
+ ["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
16077
+ ["FICT-P003" /* FICT_P003 */]: "Computed property in props pattern cannot be made reactive.",
16078
+ ["FICT-P004" /* FICT_P004 */]: "Nested props destructuring falls back to non-reactive binding; access props directly or use useProp.",
16079
+ ["FICT-S001" /* FICT_S001 */]: "State variable mutation detected outside component scope.",
16080
+ ["FICT-S002" /* FICT_S002 */]: "State variable escaped to external scope, may cause memory leaks.",
16081
+ ["FICT-E001" /* FICT_E001 */]: "Effect without reactive dependencies will run only once; consider adding state reads or removing the effect.",
16082
+ ["FICT-E002" /* FICT_E002 */]: "Effect captures reactive value that may change.",
16083
+ ["FICT-E003" /* FICT_E003 */]: "Effect cleanup function is not properly tracked.",
16084
+ ["FICT-M001" /* FICT_M001 */]: "Memo has no reactive dependencies and could be a constant.",
16085
+ ["FICT-M002" /* FICT_M002 */]: "Unnecessary memo wrapping a constant value.",
16086
+ ["FICT-M003" /* FICT_M003 */]: "Memo should not contain side effects.",
16087
+ ["FICT-C001" /* FICT_C001 */]: "Hooks should not be called conditionally.",
16088
+ ["FICT-C002" /* FICT_C002 */]: "Hooks should not be called inside loops.",
16089
+ ["FICT-C003" /* FICT_C003 */]: "Components should not be defined inside other components.",
16090
+ ["FICT-C004" /* FICT_C004 */]: "Component has no return statement and will render nothing.",
16091
+ ["FICT-J001" /* FICT_J001 */]: "Dynamic key expression may impact performance.",
16092
+ ["FICT-J002" /* FICT_J002 */]: "Missing key prop in list rendering.",
16093
+ ["FICT-J003" /* FICT_J003 */]: "Spread on native element may include unknown props.",
16094
+ ["FICT-R001" /* FICT_R001 */]: "Expression crosses reactive region boundary.",
16095
+ ["FICT-R002" /* FICT_R002 */]: "Scope escape detected, value may not be tracked.",
16096
+ ["FICT-R003" /* FICT_R003 */]: "Expression cannot be memoized automatically.",
16097
+ ["FICT-R004" /* FICT_R004 */]: "Reactive creation inside non-JSX control flow will not auto-dispose; wrap it in createScope/runInScope or move it into JSX-managed regions.",
16098
+ ["FICT-R005" /* FICT_R005 */]: "Function captures reactive variables from outer scope; pass them as parameters or memoize explicitly to avoid hidden dependencies.",
16099
+ ["FICT-X001" /* FICT_X001 */]: "Object is recreated on each render, consider memoizing.",
16100
+ ["FICT-X002" /* FICT_X002 */]: "Array is recreated on each render, consider memoizing.",
16101
+ ["FICT-X003" /* FICT_X003 */]: "Inline function in JSX props may cause unnecessary re-renders."
16102
+ };
16103
+ var DiagnosticSeverities = {
16104
+ ["FICT-P001" /* FICT_P001 */]: "warning" /* Warning */,
16105
+ ["FICT-P002" /* FICT_P002 */]: "warning" /* Warning */,
16106
+ ["FICT-P003" /* FICT_P003 */]: "warning" /* Warning */,
16107
+ ["FICT-P004" /* FICT_P004 */]: "warning" /* Warning */,
16108
+ ["FICT-S001" /* FICT_S001 */]: "error" /* Error */,
16109
+ ["FICT-S002" /* FICT_S002 */]: "warning" /* Warning */,
16110
+ ["FICT-E001" /* FICT_E001 */]: "warning" /* Warning */,
16111
+ ["FICT-E002" /* FICT_E002 */]: "info" /* Info */,
16112
+ ["FICT-E003" /* FICT_E003 */]: "warning" /* Warning */,
16113
+ ["FICT-M001" /* FICT_M001 */]: "info" /* Info */,
16114
+ ["FICT-M002" /* FICT_M002 */]: "hint" /* Hint */,
16115
+ ["FICT-M003" /* FICT_M003 */]: "error" /* Error */,
16116
+ ["FICT-C001" /* FICT_C001 */]: "error" /* Error */,
16117
+ ["FICT-C002" /* FICT_C002 */]: "error" /* Error */,
16118
+ ["FICT-C003" /* FICT_C003 */]: "warning" /* Warning */,
16119
+ ["FICT-C004" /* FICT_C004 */]: "warning" /* Warning */,
16120
+ ["FICT-J001" /* FICT_J001 */]: "info" /* Info */,
16121
+ ["FICT-J002" /* FICT_J002 */]: "warning" /* Warning */,
16122
+ ["FICT-J003" /* FICT_J003 */]: "info" /* Info */,
16123
+ ["FICT-R001" /* FICT_R001 */]: "info" /* Info */,
16124
+ ["FICT-R002" /* FICT_R002 */]: "warning" /* Warning */,
16125
+ ["FICT-R003" /* FICT_R003 */]: "info" /* Info */,
16126
+ ["FICT-R004" /* FICT_R004 */]: "warning" /* Warning */,
16127
+ ["FICT-R005" /* FICT_R005 */]: "warning" /* Warning */,
16128
+ ["FICT-X001" /* FICT_X001 */]: "hint" /* Hint */,
16129
+ ["FICT-X002" /* FICT_X002 */]: "hint" /* Hint */,
16130
+ ["FICT-X003" /* FICT_X003 */]: "hint" /* Hint */
16131
+ };
16132
+ function createDiagnostic(code, node, fileName, context) {
16133
+ const loc = node.loc;
16134
+ return {
16135
+ code,
16136
+ severity: DiagnosticSeverities[code],
16137
+ message: DiagnosticMessages[code],
16138
+ fileName,
16139
+ line: loc?.start.line ?? 0,
16140
+ column: loc?.start.column ?? 0,
16141
+ endLine: loc?.end.line,
16142
+ endColumn: loc?.end.column,
16143
+ context
16144
+ };
16145
+ }
16146
+ function reportDiagnostic(ctx, code, node, context) {
16147
+ const fileName = ctx.file?.opts?.filename || "<unknown>";
16148
+ const diagnostic = createDiagnostic(code, node, fileName, context);
16149
+ if (ctx.options?.onWarn) {
16150
+ ctx.options.onWarn({
16151
+ code: diagnostic.code,
16152
+ message: diagnostic.message,
16153
+ fileName: diagnostic.fileName,
16154
+ line: diagnostic.line,
16155
+ column: diagnostic.column
16156
+ });
16157
+ }
16158
+ }
16159
+
16122
16160
  // src/ir/ssa.ts
16123
16161
  function analyzeCFG(blocks) {
16124
16162
  const predecessors = computePredecessors(blocks);
@@ -19424,7 +19462,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19424
19462
  const isTracked = ctx.trackedVars.has(baseName2);
19425
19463
  const isSignal = ctx.signalVars?.has(baseName2) ?? false;
19426
19464
  const aliasVars = ctx.aliasVars ?? (ctx.aliasVars = /* @__PURE__ */ new Set());
19427
- const dependsOnTracked2 = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19465
+ const dependsOnTracked = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19428
19466
  const capturedTracked = ctx.externalTracked && ctx.externalTracked.has(baseName2) && !declaredVars.has(baseName2);
19429
19467
  const isShadowDeclaration = !!declKind && declaredVars.has(baseName2);
19430
19468
  const treatAsTracked = !isShadowDeclaration && isTracked;
@@ -19455,10 +19493,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19455
19493
  ctx.trackedVars.delete(baseName2);
19456
19494
  }
19457
19495
  if (declKind) {
19458
- const normalizedDecl = isStateCall2 || dependsOnTracked2 && !isDestructuringTemp ? "const" : declKind;
19496
+ const normalizedDecl = isStateCall2 || dependsOnTracked && !isDestructuringTemp ? "const" : declKind;
19459
19497
  const needsMutable = ctx.mutatedVars?.has(baseName2) ?? false;
19460
19498
  const isExternalAlias = declKind === "const" && instr.value.kind === "Identifier" && !(ctx.scopes?.byName?.has(deSSAVarName(instr.value.name)) ?? false);
19461
- const fallbackDecl = !treatAsTracked && (!dependsOnTracked2 || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
19499
+ const fallbackDecl = !treatAsTracked && (!dependsOnTracked || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
19462
19500
  declaredVars.add(baseName2);
19463
19501
  if (treatAsTracked && !isDestructuringTemp) {
19464
19502
  if (isStateCall2) {
@@ -19466,7 +19504,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19466
19504
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19467
19505
  ]);
19468
19506
  }
19469
- if (dependsOnTracked2) {
19507
+ if (dependsOnTracked) {
19470
19508
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19471
19509
  aliasVars.add(baseName2);
19472
19510
  }
@@ -19493,7 +19531,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19493
19531
  ]);
19494
19532
  }
19495
19533
  }
19496
- if (dependsOnTracked2 && !isDestructuringTemp) {
19534
+ if (dependsOnTracked && !isDestructuringTemp) {
19497
19535
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19498
19536
  aliasVars.add(baseName2);
19499
19537
  }
@@ -19534,7 +19572,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19534
19572
  if (aliasVars.has(baseName2) && !declaredVars.has(baseName2)) {
19535
19573
  throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
19536
19574
  }
19537
- if (dependsOnTracked2 && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19575
+ if (dependsOnTracked && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19538
19576
  const derivedExpr = lowerAssignedValue(true);
19539
19577
  aliasVars.add(baseName2);
19540
19578
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
@@ -19585,7 +19623,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19585
19623
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19586
19624
  ]);
19587
19625
  }
19588
- if (dependsOnTracked2) {
19626
+ if (dependsOnTracked) {
19589
19627
  const derivedExpr = lowerAssignedValue(true);
19590
19628
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19591
19629
  return t2.variableDeclaration("const", [
@@ -19612,7 +19650,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19612
19650
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19613
19651
  ]);
19614
19652
  }
19615
- if (dependsOnTracked2) {
19653
+ if (dependsOnTracked) {
19616
19654
  const derivedExpr = lowerAssignedValue(true);
19617
19655
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19618
19656
  return t2.variableDeclaration("let", [
@@ -22257,6 +22295,9 @@ function applyRegionMetadataToExpression(expr, ctx, regionOverride, options) {
22257
22295
  }
22258
22296
  function replaceIdentifiersWithOverrides(node, overrides, t2, parentKind, parentKey, skipCurrentNode = false) {
22259
22297
  const isCallTarget = parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
22298
+ if (parentKind === "VariableDeclarator" && parentKey === "id") {
22299
+ return;
22300
+ }
22260
22301
  const collectParamNames = (params) => {
22261
22302
  const names = /* @__PURE__ */ new Set();
22262
22303
  const addName = (n) => {
@@ -23623,7 +23664,7 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23623
23664
  if (isKeyed) {
23624
23665
  ctx.helpersUsed.add("keyedList");
23625
23666
  } else {
23626
- ctx.helpersUsed.add("list");
23667
+ ctx.helpersUsed.add("keyedList");
23627
23668
  ctx.helpersUsed.add("createElement");
23628
23669
  }
23629
23670
  const prevHoistedTemplates = ctx.hoistedTemplates;
@@ -23664,6 +23705,17 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23664
23705
  overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
23665
23706
  }
23666
23707
  if (Object.keys(overrides).length > 0) {
23708
+ if (t2.isBlockStatement(callbackExpr.body)) {
23709
+ for (const stmt of callbackExpr.body.body) {
23710
+ if (!t2.isVariableDeclaration(stmt)) continue;
23711
+ for (const decl of stmt.declarations) {
23712
+ if (!t2.isIdentifier(decl.id) || !decl.init) continue;
23713
+ const replacement = t2.cloneNode(decl.init, true);
23714
+ replaceIdentifiersWithOverrides(replacement, overrides, t2, callbackExpr.type, "body");
23715
+ overrides[decl.id.name] = () => t2.cloneNode(replacement, true);
23716
+ }
23717
+ }
23718
+ }
23667
23719
  if (t2.isBlockStatement(callbackExpr.body)) {
23668
23720
  replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
23669
23721
  } else {
@@ -23742,14 +23794,22 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23742
23794
  );
23743
23795
  } else {
23744
23796
  statements.push(...hoistedStatements);
23797
+ const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : "__item" : "__item";
23798
+ const indexParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[1]) ? callbackExpr.params[1].name : "__index" : "__index";
23799
+ const hasIndexParam = (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
23800
+ const keyFn = t2.arrowFunctionExpression(
23801
+ [t2.identifier(itemParamName), t2.identifier(indexParamName)],
23802
+ t2.identifier(indexParamName)
23803
+ );
23745
23804
  statements.push(
23746
23805
  t2.variableDeclaration("const", [
23747
23806
  t2.variableDeclarator(
23748
23807
  listId,
23749
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.list), [
23808
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.keyedList), [
23750
23809
  t2.arrowFunctionExpression([], arrayExpr),
23810
+ keyFn,
23751
23811
  callbackExpr,
23752
- t2.identifier(RUNTIME_ALIASES.createElement)
23812
+ t2.booleanLiteral(hasIndexParam)
23753
23813
  ])
23754
23814
  )
23755
23815
  ])
@@ -24394,55 +24454,94 @@ function lowerFunctionWithRegions(fn, ctx) {
24394
24454
  let supported = true;
24395
24455
  let usesUseProp = false;
24396
24456
  let usesPropsRest = false;
24397
- for (const prop of pattern.properties) {
24398
- if (t2.isObjectProperty(prop) && !prop.computed) {
24399
- const keyName = t2.isIdentifier(prop.key) ? prop.key.name : t2.isStringLiteral(prop.key) ? prop.key.value : t2.isNumericLiteral(prop.key) ? String(prop.key.value) : null;
24400
- if (!keyName || !t2.isIdentifier(prop.value)) {
24457
+ let warnedNested = false;
24458
+ const memberExprForKey = (base, key) => t2.memberExpression(base, t2.identifier(key), false);
24459
+ const buildDestructure = (objectPattern, baseExpr, allowRest) => {
24460
+ for (const prop of objectPattern.properties) {
24461
+ if (t2.isObjectProperty(prop) && !prop.computed) {
24462
+ const keyName = t2.isIdentifier(prop.key) ? prop.key.name : t2.isStringLiteral(prop.key) ? prop.key.value : t2.isNumericLiteral(prop.key) ? String(prop.key.value) : null;
24463
+ if (!keyName) {
24464
+ reportDiagnostic(ctx, "FICT-P003" /* FICT_P003 */, prop);
24465
+ supported = false;
24466
+ warnedNested = true;
24467
+ break;
24468
+ }
24469
+ if (allowRest) {
24470
+ excludeKeys.push(t2.stringLiteral(keyName));
24471
+ }
24472
+ const member = memberExprForKey(baseExpr, keyName);
24473
+ const value = prop.value;
24474
+ if (t2.isIdentifier(value)) {
24475
+ const shouldUseProp = !calledIdentifiers.has(value.name);
24476
+ if (shouldUseProp) {
24477
+ usesUseProp = true;
24478
+ propsPlanAliases.add(value.name);
24479
+ }
24480
+ stmts.push(
24481
+ t2.variableDeclaration("const", [
24482
+ t2.variableDeclarator(
24483
+ t2.identifier(value.name),
24484
+ shouldUseProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24485
+ t2.arrowFunctionExpression([], member)
24486
+ ]) : member
24487
+ )
24488
+ ])
24489
+ );
24490
+ continue;
24491
+ }
24492
+ if (t2.isObjectPattern(value)) {
24493
+ buildDestructure(value, member, false);
24494
+ if (!supported) break;
24495
+ continue;
24496
+ }
24497
+ if (t2.isAssignmentPattern(value) && t2.isIdentifier(value.left)) {
24498
+ const shouldUseProp = !calledIdentifiers.has(value.left.name);
24499
+ if (shouldUseProp) {
24500
+ usesUseProp = true;
24501
+ propsPlanAliases.add(value.left.name);
24502
+ }
24503
+ const baseInit = t2.logicalExpression("??", member, value.right);
24504
+ const init = shouldUseProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24505
+ t2.arrowFunctionExpression([], baseInit)
24506
+ ]) : baseInit;
24507
+ stmts.push(
24508
+ t2.variableDeclaration("const", [
24509
+ t2.variableDeclarator(t2.identifier(value.left.name), init)
24510
+ ])
24511
+ );
24512
+ continue;
24513
+ }
24401
24514
  supported = false;
24515
+ if (!warnedNested) {
24516
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24517
+ warnedNested = true;
24518
+ }
24402
24519
  break;
24403
- }
24404
- excludeKeys.push(t2.stringLiteral(keyName));
24405
- const member = t2.memberExpression(t2.identifier("__props"), t2.identifier(keyName), false);
24406
- if (!calledIdentifiers.has(prop.value.name)) {
24407
- usesUseProp = true;
24408
- propsPlanAliases.add(prop.value.name);
24520
+ } else if (t2.isRestElement(prop) && allowRest && t2.isIdentifier(prop.argument)) {
24521
+ usesPropsRest = true;
24409
24522
  stmts.push(
24410
24523
  t2.variableDeclaration("const", [
24411
24524
  t2.variableDeclarator(
24412
- t2.identifier(prop.value.name),
24413
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24414
- t2.arrowFunctionExpression([], member)
24525
+ t2.identifier(prop.argument.name),
24526
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), [
24527
+ baseExpr,
24528
+ t2.arrayExpression(excludeKeys)
24415
24529
  ])
24416
24530
  )
24417
24531
  ])
24418
24532
  );
24533
+ continue;
24419
24534
  } else {
24420
- stmts.push(
24421
- t2.variableDeclaration("const", [
24422
- t2.variableDeclarator(t2.identifier(prop.value.name), member)
24423
- ])
24424
- );
24535
+ supported = false;
24536
+ if (!warnedNested) {
24537
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24538
+ warnedNested = true;
24539
+ }
24540
+ break;
24425
24541
  }
24426
- continue;
24427
24542
  }
24428
- if (t2.isRestElement(prop) && t2.isIdentifier(prop.argument)) {
24429
- usesPropsRest = true;
24430
- stmts.push(
24431
- t2.variableDeclaration("const", [
24432
- t2.variableDeclarator(
24433
- t2.identifier(prop.argument.name),
24434
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), [
24435
- t2.identifier("__props"),
24436
- t2.arrayExpression(excludeKeys)
24437
- ])
24438
- )
24439
- ])
24440
- );
24441
- continue;
24442
- }
24443
- supported = false;
24444
- break;
24445
- }
24543
+ };
24544
+ buildDestructure(pattern, t2.identifier("__props"), true);
24446
24545
  if (supported) {
24447
24546
  propsDestructurePlan = {
24448
24547
  statements: stmts,
@@ -24610,6 +24709,38 @@ function flattenRegions(regions) {
24610
24709
  });
24611
24710
  }
24612
24711
 
24712
+ // src/utils.ts
24713
+ function isStateCall(node, t2) {
24714
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
24715
+ }
24716
+ function isEffectCall(node, t2) {
24717
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
24718
+ }
24719
+ function getRootIdentifier(expr, t2) {
24720
+ if (t2.isIdentifier(expr)) {
24721
+ return expr;
24722
+ }
24723
+ if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
24724
+ return getRootIdentifier(expr.object, t2);
24725
+ }
24726
+ if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
24727
+ return getRootIdentifier(expr.object, t2);
24728
+ }
24729
+ if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
24730
+ return getRootIdentifier(expr.callee, t2);
24731
+ }
24732
+ if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
24733
+ return getRootIdentifier(expr.callee, t2);
24734
+ }
24735
+ if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
24736
+ return getRootIdentifier(expr.expression, t2);
24737
+ }
24738
+ if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
24739
+ return getRootIdentifier(expr.expression, t2);
24740
+ }
24741
+ return null;
24742
+ }
24743
+
24613
24744
  // src/index.ts
24614
24745
  function stripMacroImports(path, t2) {
24615
24746
  path.traverse({
package/dist/index.js CHANGED
@@ -14131,7 +14131,6 @@ var RUNTIME_HELPERS = {
14131
14131
  runInScope: "runInScope",
14132
14132
  createElement: "createElement",
14133
14133
  conditional: "createConditional",
14134
- list: "createList",
14135
14134
  keyedList: "createKeyedList",
14136
14135
  insert: "insert",
14137
14136
  onDestroy: "onDestroy",
@@ -14144,11 +14143,6 @@ var RUNTIME_HELPERS = {
14144
14143
  callEventHandler: "callEventHandler",
14145
14144
  bindRef: "bindRef",
14146
14145
  toNodeArray: "toNodeArray",
14147
- createKeyedListContainer: "createKeyedListContainer",
14148
- createKeyedBlock: "createKeyedBlock",
14149
- moveMarkerBlock: "moveMarkerBlock",
14150
- destroyMarkerBlock: "destroyMarkerBlock",
14151
- getFirstNodeAfter: "getFirstNodeAfter",
14152
14146
  template: "template",
14153
14147
  delegateEvents: "delegateEvents"
14154
14148
  };
@@ -14172,7 +14166,6 @@ var RUNTIME_ALIASES = {
14172
14166
  runInScope: "runInScope",
14173
14167
  createElement: "createElement",
14174
14168
  conditional: "createConditional",
14175
- list: "createList",
14176
14169
  keyedList: "createKeyedList",
14177
14170
  insert: "insert",
14178
14171
  onDestroy: "onDestroy",
@@ -14185,11 +14178,6 @@ var RUNTIME_ALIASES = {
14185
14178
  callEventHandler: "callEventHandler",
14186
14179
  bindRef: "bindRef",
14187
14180
  toNodeArray: "toNodeArray",
14188
- createKeyedListContainer: "createKeyedListContainer",
14189
- createKeyedBlock: "createKeyedBlock",
14190
- moveMarkerBlock: "moveMarkerBlock",
14191
- destroyMarkerBlock: "destroyMarkerBlock",
14192
- getFirstNodeAfter: "getFirstNodeAfter",
14193
14181
  template: "template",
14194
14182
  delegateEvents: "delegateEvents"
14195
14183
  };
@@ -14306,9 +14294,13 @@ var HIRError = class extends Error {
14306
14294
  }
14307
14295
  };
14308
14296
  var SSA_PATTERN = /\$\$ssa\d+$/;
14297
+ var GENERATED_SSA_NAMES = /* @__PURE__ */ new Set();
14309
14298
  function getSSABaseName(name) {
14310
14299
  if (name.startsWith("__")) return name;
14311
- return name.replace(SSA_PATTERN, "");
14300
+ if (GENERATED_SSA_NAMES.has(name)) {
14301
+ return name.replace(SSA_PATTERN, "");
14302
+ }
14303
+ return SSA_PATTERN.test(name) ? name : name;
14312
14304
  }
14313
14305
  function extractDependencyPath(expr) {
14314
14306
  if (expr.kind === "Identifier") {
@@ -16038,38 +16030,6 @@ function debugEnabled(flag) {
16038
16030
  return parts.includes(normalized) || parts.includes("all");
16039
16031
  }
16040
16032
 
16041
- // src/utils.ts
16042
- function isStateCall(node, t2) {
16043
- return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
16044
- }
16045
- function isEffectCall(node, t2) {
16046
- return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
16047
- }
16048
- function getRootIdentifier(expr, t2) {
16049
- if (t2.isIdentifier(expr)) {
16050
- return expr;
16051
- }
16052
- if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
16053
- return getRootIdentifier(expr.object, t2);
16054
- }
16055
- if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
16056
- return getRootIdentifier(expr.object, t2);
16057
- }
16058
- if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
16059
- return getRootIdentifier(expr.callee, t2);
16060
- }
16061
- if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
16062
- return getRootIdentifier(expr.callee, t2);
16063
- }
16064
- if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
16065
- return getRootIdentifier(expr.expression, t2);
16066
- }
16067
- if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
16068
- return getRootIdentifier(expr.expression, t2);
16069
- }
16070
- return null;
16071
- }
16072
-
16073
16033
  // src/fine-grained-dom.ts
16074
16034
  function normalizeDependencyKey(name) {
16075
16035
  return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
@@ -16078,35 +16038,113 @@ function applyRegionMetadata(state, options) {
16078
16038
  if (!options.region) return;
16079
16039
  const region = options.region;
16080
16040
  state.regionMetadata = region;
16081
- if (region.dependencies.size > 0) {
16082
- state.identifierOverrides = state.identifierOverrides ?? {};
16083
- const dependencyGetter = options.dependencyGetter ?? null;
16084
- if (!dependencyGetter) {
16085
- return;
16086
- }
16087
- for (const dep of region.dependencies) {
16088
- const key = normalizeDependencyKey(dep);
16089
- state.identifierOverrides[key] = () => dependencyGetter(dep);
16090
- const base = key.split(".")[0];
16091
- if (base && !state.identifierOverrides[base]) {
16092
- state.identifierOverrides[base] = () => dependencyGetter(base);
16093
- }
16041
+ if (region.dependencies.size === 0) return;
16042
+ const dependencyGetter = options.dependencyGetter;
16043
+ if (!dependencyGetter) return;
16044
+ state.identifierOverrides = state.identifierOverrides ?? {};
16045
+ for (const dep of region.dependencies) {
16046
+ const key = normalizeDependencyKey(dep);
16047
+ state.identifierOverrides[key] = () => dependencyGetter(dep);
16048
+ const base = key.split(".")[0];
16049
+ if (base && !state.identifierOverrides[base]) {
16050
+ state.identifierOverrides[base] = () => dependencyGetter(base);
16094
16051
  }
16095
16052
  }
16096
16053
  }
16097
16054
  function shouldMemoizeRegion(region) {
16098
- if (region.dependencies.size > 0) {
16099
- return true;
16100
- }
16101
- if (region.hasControlFlow) {
16102
- return true;
16103
- }
16104
- if (region.hasReactiveWrites) {
16105
- return true;
16106
- }
16055
+ if (region.dependencies.size > 0) return true;
16056
+ if (region.hasControlFlow) return true;
16057
+ if (region.hasReactiveWrites) return true;
16107
16058
  return false;
16108
16059
  }
16109
16060
 
16061
+ // src/validation.ts
16062
+ var DiagnosticMessages = {
16063
+ ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
16064
+ ["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
16065
+ ["FICT-P003" /* FICT_P003 */]: "Computed property in props pattern cannot be made reactive.",
16066
+ ["FICT-P004" /* FICT_P004 */]: "Nested props destructuring falls back to non-reactive binding; access props directly or use useProp.",
16067
+ ["FICT-S001" /* FICT_S001 */]: "State variable mutation detected outside component scope.",
16068
+ ["FICT-S002" /* FICT_S002 */]: "State variable escaped to external scope, may cause memory leaks.",
16069
+ ["FICT-E001" /* FICT_E001 */]: "Effect without reactive dependencies will run only once; consider adding state reads or removing the effect.",
16070
+ ["FICT-E002" /* FICT_E002 */]: "Effect captures reactive value that may change.",
16071
+ ["FICT-E003" /* FICT_E003 */]: "Effect cleanup function is not properly tracked.",
16072
+ ["FICT-M001" /* FICT_M001 */]: "Memo has no reactive dependencies and could be a constant.",
16073
+ ["FICT-M002" /* FICT_M002 */]: "Unnecessary memo wrapping a constant value.",
16074
+ ["FICT-M003" /* FICT_M003 */]: "Memo should not contain side effects.",
16075
+ ["FICT-C001" /* FICT_C001 */]: "Hooks should not be called conditionally.",
16076
+ ["FICT-C002" /* FICT_C002 */]: "Hooks should not be called inside loops.",
16077
+ ["FICT-C003" /* FICT_C003 */]: "Components should not be defined inside other components.",
16078
+ ["FICT-C004" /* FICT_C004 */]: "Component has no return statement and will render nothing.",
16079
+ ["FICT-J001" /* FICT_J001 */]: "Dynamic key expression may impact performance.",
16080
+ ["FICT-J002" /* FICT_J002 */]: "Missing key prop in list rendering.",
16081
+ ["FICT-J003" /* FICT_J003 */]: "Spread on native element may include unknown props.",
16082
+ ["FICT-R001" /* FICT_R001 */]: "Expression crosses reactive region boundary.",
16083
+ ["FICT-R002" /* FICT_R002 */]: "Scope escape detected, value may not be tracked.",
16084
+ ["FICT-R003" /* FICT_R003 */]: "Expression cannot be memoized automatically.",
16085
+ ["FICT-R004" /* FICT_R004 */]: "Reactive creation inside non-JSX control flow will not auto-dispose; wrap it in createScope/runInScope or move it into JSX-managed regions.",
16086
+ ["FICT-R005" /* FICT_R005 */]: "Function captures reactive variables from outer scope; pass them as parameters or memoize explicitly to avoid hidden dependencies.",
16087
+ ["FICT-X001" /* FICT_X001 */]: "Object is recreated on each render, consider memoizing.",
16088
+ ["FICT-X002" /* FICT_X002 */]: "Array is recreated on each render, consider memoizing.",
16089
+ ["FICT-X003" /* FICT_X003 */]: "Inline function in JSX props may cause unnecessary re-renders."
16090
+ };
16091
+ var DiagnosticSeverities = {
16092
+ ["FICT-P001" /* FICT_P001 */]: "warning" /* Warning */,
16093
+ ["FICT-P002" /* FICT_P002 */]: "warning" /* Warning */,
16094
+ ["FICT-P003" /* FICT_P003 */]: "warning" /* Warning */,
16095
+ ["FICT-P004" /* FICT_P004 */]: "warning" /* Warning */,
16096
+ ["FICT-S001" /* FICT_S001 */]: "error" /* Error */,
16097
+ ["FICT-S002" /* FICT_S002 */]: "warning" /* Warning */,
16098
+ ["FICT-E001" /* FICT_E001 */]: "warning" /* Warning */,
16099
+ ["FICT-E002" /* FICT_E002 */]: "info" /* Info */,
16100
+ ["FICT-E003" /* FICT_E003 */]: "warning" /* Warning */,
16101
+ ["FICT-M001" /* FICT_M001 */]: "info" /* Info */,
16102
+ ["FICT-M002" /* FICT_M002 */]: "hint" /* Hint */,
16103
+ ["FICT-M003" /* FICT_M003 */]: "error" /* Error */,
16104
+ ["FICT-C001" /* FICT_C001 */]: "error" /* Error */,
16105
+ ["FICT-C002" /* FICT_C002 */]: "error" /* Error */,
16106
+ ["FICT-C003" /* FICT_C003 */]: "warning" /* Warning */,
16107
+ ["FICT-C004" /* FICT_C004 */]: "warning" /* Warning */,
16108
+ ["FICT-J001" /* FICT_J001 */]: "info" /* Info */,
16109
+ ["FICT-J002" /* FICT_J002 */]: "warning" /* Warning */,
16110
+ ["FICT-J003" /* FICT_J003 */]: "info" /* Info */,
16111
+ ["FICT-R001" /* FICT_R001 */]: "info" /* Info */,
16112
+ ["FICT-R002" /* FICT_R002 */]: "warning" /* Warning */,
16113
+ ["FICT-R003" /* FICT_R003 */]: "info" /* Info */,
16114
+ ["FICT-R004" /* FICT_R004 */]: "warning" /* Warning */,
16115
+ ["FICT-R005" /* FICT_R005 */]: "warning" /* Warning */,
16116
+ ["FICT-X001" /* FICT_X001 */]: "hint" /* Hint */,
16117
+ ["FICT-X002" /* FICT_X002 */]: "hint" /* Hint */,
16118
+ ["FICT-X003" /* FICT_X003 */]: "hint" /* Hint */
16119
+ };
16120
+ function createDiagnostic(code, node, fileName, context) {
16121
+ const loc = node.loc;
16122
+ return {
16123
+ code,
16124
+ severity: DiagnosticSeverities[code],
16125
+ message: DiagnosticMessages[code],
16126
+ fileName,
16127
+ line: loc?.start.line ?? 0,
16128
+ column: loc?.start.column ?? 0,
16129
+ endLine: loc?.end.line,
16130
+ endColumn: loc?.end.column,
16131
+ context
16132
+ };
16133
+ }
16134
+ function reportDiagnostic(ctx, code, node, context) {
16135
+ const fileName = ctx.file?.opts?.filename || "<unknown>";
16136
+ const diagnostic = createDiagnostic(code, node, fileName, context);
16137
+ if (ctx.options?.onWarn) {
16138
+ ctx.options.onWarn({
16139
+ code: diagnostic.code,
16140
+ message: diagnostic.message,
16141
+ fileName: diagnostic.fileName,
16142
+ line: diagnostic.line,
16143
+ column: diagnostic.column
16144
+ });
16145
+ }
16146
+ }
16147
+
16110
16148
  // src/ir/ssa.ts
16111
16149
  function analyzeCFG(blocks) {
16112
16150
  const predecessors = computePredecessors(blocks);
@@ -19412,7 +19450,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19412
19450
  const isTracked = ctx.trackedVars.has(baseName2);
19413
19451
  const isSignal = ctx.signalVars?.has(baseName2) ?? false;
19414
19452
  const aliasVars = ctx.aliasVars ?? (ctx.aliasVars = /* @__PURE__ */ new Set());
19415
- const dependsOnTracked2 = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19453
+ const dependsOnTracked = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19416
19454
  const capturedTracked = ctx.externalTracked && ctx.externalTracked.has(baseName2) && !declaredVars.has(baseName2);
19417
19455
  const isShadowDeclaration = !!declKind && declaredVars.has(baseName2);
19418
19456
  const treatAsTracked = !isShadowDeclaration && isTracked;
@@ -19443,10 +19481,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19443
19481
  ctx.trackedVars.delete(baseName2);
19444
19482
  }
19445
19483
  if (declKind) {
19446
- const normalizedDecl = isStateCall2 || dependsOnTracked2 && !isDestructuringTemp ? "const" : declKind;
19484
+ const normalizedDecl = isStateCall2 || dependsOnTracked && !isDestructuringTemp ? "const" : declKind;
19447
19485
  const needsMutable = ctx.mutatedVars?.has(baseName2) ?? false;
19448
19486
  const isExternalAlias = declKind === "const" && instr.value.kind === "Identifier" && !(ctx.scopes?.byName?.has(deSSAVarName(instr.value.name)) ?? false);
19449
- const fallbackDecl = !treatAsTracked && (!dependsOnTracked2 || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
19487
+ const fallbackDecl = !treatAsTracked && (!dependsOnTracked || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
19450
19488
  declaredVars.add(baseName2);
19451
19489
  if (treatAsTracked && !isDestructuringTemp) {
19452
19490
  if (isStateCall2) {
@@ -19454,7 +19492,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19454
19492
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19455
19493
  ]);
19456
19494
  }
19457
- if (dependsOnTracked2) {
19495
+ if (dependsOnTracked) {
19458
19496
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19459
19497
  aliasVars.add(baseName2);
19460
19498
  }
@@ -19481,7 +19519,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19481
19519
  ]);
19482
19520
  }
19483
19521
  }
19484
- if (dependsOnTracked2 && !isDestructuringTemp) {
19522
+ if (dependsOnTracked && !isDestructuringTemp) {
19485
19523
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19486
19524
  aliasVars.add(baseName2);
19487
19525
  }
@@ -19522,7 +19560,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19522
19560
  if (aliasVars.has(baseName2) && !declaredVars.has(baseName2)) {
19523
19561
  throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
19524
19562
  }
19525
- if (dependsOnTracked2 && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19563
+ if (dependsOnTracked && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19526
19564
  const derivedExpr = lowerAssignedValue(true);
19527
19565
  aliasVars.add(baseName2);
19528
19566
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
@@ -19573,7 +19611,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19573
19611
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19574
19612
  ]);
19575
19613
  }
19576
- if (dependsOnTracked2) {
19614
+ if (dependsOnTracked) {
19577
19615
  const derivedExpr = lowerAssignedValue(true);
19578
19616
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19579
19617
  return t2.variableDeclaration("const", [
@@ -19600,7 +19638,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19600
19638
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19601
19639
  ]);
19602
19640
  }
19603
- if (dependsOnTracked2) {
19641
+ if (dependsOnTracked) {
19604
19642
  const derivedExpr = lowerAssignedValue(true);
19605
19643
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19606
19644
  return t2.variableDeclaration("let", [
@@ -22245,6 +22283,9 @@ function applyRegionMetadataToExpression(expr, ctx, regionOverride, options) {
22245
22283
  }
22246
22284
  function replaceIdentifiersWithOverrides(node, overrides, t2, parentKind, parentKey, skipCurrentNode = false) {
22247
22285
  const isCallTarget = parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
22286
+ if (parentKind === "VariableDeclarator" && parentKey === "id") {
22287
+ return;
22288
+ }
22248
22289
  const collectParamNames = (params) => {
22249
22290
  const names = /* @__PURE__ */ new Set();
22250
22291
  const addName = (n) => {
@@ -23611,7 +23652,7 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23611
23652
  if (isKeyed) {
23612
23653
  ctx.helpersUsed.add("keyedList");
23613
23654
  } else {
23614
- ctx.helpersUsed.add("list");
23655
+ ctx.helpersUsed.add("keyedList");
23615
23656
  ctx.helpersUsed.add("createElement");
23616
23657
  }
23617
23658
  const prevHoistedTemplates = ctx.hoistedTemplates;
@@ -23652,6 +23693,17 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23652
23693
  overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
23653
23694
  }
23654
23695
  if (Object.keys(overrides).length > 0) {
23696
+ if (t2.isBlockStatement(callbackExpr.body)) {
23697
+ for (const stmt of callbackExpr.body.body) {
23698
+ if (!t2.isVariableDeclaration(stmt)) continue;
23699
+ for (const decl of stmt.declarations) {
23700
+ if (!t2.isIdentifier(decl.id) || !decl.init) continue;
23701
+ const replacement = t2.cloneNode(decl.init, true);
23702
+ replaceIdentifiersWithOverrides(replacement, overrides, t2, callbackExpr.type, "body");
23703
+ overrides[decl.id.name] = () => t2.cloneNode(replacement, true);
23704
+ }
23705
+ }
23706
+ }
23655
23707
  if (t2.isBlockStatement(callbackExpr.body)) {
23656
23708
  replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
23657
23709
  } else {
@@ -23730,14 +23782,22 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23730
23782
  );
23731
23783
  } else {
23732
23784
  statements.push(...hoistedStatements);
23785
+ const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : "__item" : "__item";
23786
+ const indexParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[1]) ? callbackExpr.params[1].name : "__index" : "__index";
23787
+ const hasIndexParam = (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
23788
+ const keyFn = t2.arrowFunctionExpression(
23789
+ [t2.identifier(itemParamName), t2.identifier(indexParamName)],
23790
+ t2.identifier(indexParamName)
23791
+ );
23733
23792
  statements.push(
23734
23793
  t2.variableDeclaration("const", [
23735
23794
  t2.variableDeclarator(
23736
23795
  listId,
23737
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.list), [
23796
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.keyedList), [
23738
23797
  t2.arrowFunctionExpression([], arrayExpr),
23798
+ keyFn,
23739
23799
  callbackExpr,
23740
- t2.identifier(RUNTIME_ALIASES.createElement)
23800
+ t2.booleanLiteral(hasIndexParam)
23741
23801
  ])
23742
23802
  )
23743
23803
  ])
@@ -24382,55 +24442,94 @@ function lowerFunctionWithRegions(fn, ctx) {
24382
24442
  let supported = true;
24383
24443
  let usesUseProp = false;
24384
24444
  let usesPropsRest = false;
24385
- for (const prop of pattern.properties) {
24386
- if (t2.isObjectProperty(prop) && !prop.computed) {
24387
- const keyName = t2.isIdentifier(prop.key) ? prop.key.name : t2.isStringLiteral(prop.key) ? prop.key.value : t2.isNumericLiteral(prop.key) ? String(prop.key.value) : null;
24388
- if (!keyName || !t2.isIdentifier(prop.value)) {
24445
+ let warnedNested = false;
24446
+ const memberExprForKey = (base, key) => t2.memberExpression(base, t2.identifier(key), false);
24447
+ const buildDestructure = (objectPattern, baseExpr, allowRest) => {
24448
+ for (const prop of objectPattern.properties) {
24449
+ if (t2.isObjectProperty(prop) && !prop.computed) {
24450
+ const keyName = t2.isIdentifier(prop.key) ? prop.key.name : t2.isStringLiteral(prop.key) ? prop.key.value : t2.isNumericLiteral(prop.key) ? String(prop.key.value) : null;
24451
+ if (!keyName) {
24452
+ reportDiagnostic(ctx, "FICT-P003" /* FICT_P003 */, prop);
24453
+ supported = false;
24454
+ warnedNested = true;
24455
+ break;
24456
+ }
24457
+ if (allowRest) {
24458
+ excludeKeys.push(t2.stringLiteral(keyName));
24459
+ }
24460
+ const member = memberExprForKey(baseExpr, keyName);
24461
+ const value = prop.value;
24462
+ if (t2.isIdentifier(value)) {
24463
+ const shouldUseProp = !calledIdentifiers.has(value.name);
24464
+ if (shouldUseProp) {
24465
+ usesUseProp = true;
24466
+ propsPlanAliases.add(value.name);
24467
+ }
24468
+ stmts.push(
24469
+ t2.variableDeclaration("const", [
24470
+ t2.variableDeclarator(
24471
+ t2.identifier(value.name),
24472
+ shouldUseProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24473
+ t2.arrowFunctionExpression([], member)
24474
+ ]) : member
24475
+ )
24476
+ ])
24477
+ );
24478
+ continue;
24479
+ }
24480
+ if (t2.isObjectPattern(value)) {
24481
+ buildDestructure(value, member, false);
24482
+ if (!supported) break;
24483
+ continue;
24484
+ }
24485
+ if (t2.isAssignmentPattern(value) && t2.isIdentifier(value.left)) {
24486
+ const shouldUseProp = !calledIdentifiers.has(value.left.name);
24487
+ if (shouldUseProp) {
24488
+ usesUseProp = true;
24489
+ propsPlanAliases.add(value.left.name);
24490
+ }
24491
+ const baseInit = t2.logicalExpression("??", member, value.right);
24492
+ const init = shouldUseProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24493
+ t2.arrowFunctionExpression([], baseInit)
24494
+ ]) : baseInit;
24495
+ stmts.push(
24496
+ t2.variableDeclaration("const", [
24497
+ t2.variableDeclarator(t2.identifier(value.left.name), init)
24498
+ ])
24499
+ );
24500
+ continue;
24501
+ }
24389
24502
  supported = false;
24503
+ if (!warnedNested) {
24504
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24505
+ warnedNested = true;
24506
+ }
24390
24507
  break;
24391
- }
24392
- excludeKeys.push(t2.stringLiteral(keyName));
24393
- const member = t2.memberExpression(t2.identifier("__props"), t2.identifier(keyName), false);
24394
- if (!calledIdentifiers.has(prop.value.name)) {
24395
- usesUseProp = true;
24396
- propsPlanAliases.add(prop.value.name);
24508
+ } else if (t2.isRestElement(prop) && allowRest && t2.isIdentifier(prop.argument)) {
24509
+ usesPropsRest = true;
24397
24510
  stmts.push(
24398
24511
  t2.variableDeclaration("const", [
24399
24512
  t2.variableDeclarator(
24400
- t2.identifier(prop.value.name),
24401
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24402
- t2.arrowFunctionExpression([], member)
24513
+ t2.identifier(prop.argument.name),
24514
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), [
24515
+ baseExpr,
24516
+ t2.arrayExpression(excludeKeys)
24403
24517
  ])
24404
24518
  )
24405
24519
  ])
24406
24520
  );
24521
+ continue;
24407
24522
  } else {
24408
- stmts.push(
24409
- t2.variableDeclaration("const", [
24410
- t2.variableDeclarator(t2.identifier(prop.value.name), member)
24411
- ])
24412
- );
24523
+ supported = false;
24524
+ if (!warnedNested) {
24525
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24526
+ warnedNested = true;
24527
+ }
24528
+ break;
24413
24529
  }
24414
- continue;
24415
24530
  }
24416
- if (t2.isRestElement(prop) && t2.isIdentifier(prop.argument)) {
24417
- usesPropsRest = true;
24418
- stmts.push(
24419
- t2.variableDeclaration("const", [
24420
- t2.variableDeclarator(
24421
- t2.identifier(prop.argument.name),
24422
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), [
24423
- t2.identifier("__props"),
24424
- t2.arrayExpression(excludeKeys)
24425
- ])
24426
- )
24427
- ])
24428
- );
24429
- continue;
24430
- }
24431
- supported = false;
24432
- break;
24433
- }
24531
+ };
24532
+ buildDestructure(pattern, t2.identifier("__props"), true);
24434
24533
  if (supported) {
24435
24534
  propsDestructurePlan = {
24436
24535
  statements: stmts,
@@ -24598,6 +24697,38 @@ function flattenRegions(regions) {
24598
24697
  });
24599
24698
  }
24600
24699
 
24700
+ // src/utils.ts
24701
+ function isStateCall(node, t2) {
24702
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
24703
+ }
24704
+ function isEffectCall(node, t2) {
24705
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
24706
+ }
24707
+ function getRootIdentifier(expr, t2) {
24708
+ if (t2.isIdentifier(expr)) {
24709
+ return expr;
24710
+ }
24711
+ if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
24712
+ return getRootIdentifier(expr.object, t2);
24713
+ }
24714
+ if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
24715
+ return getRootIdentifier(expr.object, t2);
24716
+ }
24717
+ if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
24718
+ return getRootIdentifier(expr.callee, t2);
24719
+ }
24720
+ if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
24721
+ return getRootIdentifier(expr.callee, t2);
24722
+ }
24723
+ if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
24724
+ return getRootIdentifier(expr.expression, t2);
24725
+ }
24726
+ if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
24727
+ return getRootIdentifier(expr.expression, t2);
24728
+ }
24729
+ return null;
24730
+ }
24731
+
24601
24732
  // src/index.ts
24602
24733
  function stripMacroImports(path, t2) {
24603
24734
  path.traverse({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fictjs/compiler",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "Babel plugin for Fict Compiler",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -45,7 +45,7 @@
45
45
  "@types/babel__helper-plugin-utils": "^7.10.3",
46
46
  "@types/babel__traverse": "^7.28.0",
47
47
  "tsup": "^8.5.1",
48
- "@fictjs/runtime": "0.0.11"
48
+ "@fictjs/runtime": "0.0.13"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "tsup src/index.ts --format cjs,esm --dts",