@fictjs/compiler 0.0.12 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14109,8 +14109,34 @@ var require_lib3 = __commonJS({
14109
14109
  // src/index.ts
14110
14110
  import { declare } from "@babel/helper-plugin-utils";
14111
14111
 
14112
+ // ../runtime/src/delegated-events.ts
14113
+ var DelegatedEventNames = [
14114
+ "beforeinput",
14115
+ "click",
14116
+ "dblclick",
14117
+ "contextmenu",
14118
+ "focusin",
14119
+ "focusout",
14120
+ "input",
14121
+ "keydown",
14122
+ "keyup",
14123
+ "mousedown",
14124
+ "mousemove",
14125
+ "mouseout",
14126
+ "mouseover",
14127
+ "mouseup",
14128
+ "pointerdown",
14129
+ "pointermove",
14130
+ "pointerout",
14131
+ "pointerover",
14132
+ "pointerup",
14133
+ "touchend",
14134
+ "touchmove",
14135
+ "touchstart"
14136
+ ];
14137
+
14112
14138
  // src/constants.ts
14113
- var RUNTIME_MODULE = "@fictjs/runtime";
14139
+ var RUNTIME_MODULE = "@fictjs/runtime/internal";
14114
14140
  var RUNTIME_HELPERS = {
14115
14141
  signal: "createSignal",
14116
14142
  createSelector: "createSelector",
@@ -14127,11 +14153,10 @@ var RUNTIME_HELPERS = {
14127
14153
  propGetter: "__fictProp",
14128
14154
  propsRest: "__fictPropsRest",
14129
14155
  mergeProps: "mergeProps",
14130
- useProp: "useProp",
14156
+ prop: "prop",
14131
14157
  runInScope: "runInScope",
14132
14158
  createElement: "createElement",
14133
14159
  conditional: "createConditional",
14134
- list: "createList",
14135
14160
  keyedList: "createKeyedList",
14136
14161
  insert: "insert",
14137
14162
  onDestroy: "onDestroy",
@@ -14144,11 +14169,6 @@ var RUNTIME_HELPERS = {
14144
14169
  callEventHandler: "callEventHandler",
14145
14170
  bindRef: "bindRef",
14146
14171
  toNodeArray: "toNodeArray",
14147
- createKeyedListContainer: "createKeyedListContainer",
14148
- createKeyedBlock: "createKeyedBlock",
14149
- moveMarkerBlock: "moveMarkerBlock",
14150
- destroyMarkerBlock: "destroyMarkerBlock",
14151
- getFirstNodeAfter: "getFirstNodeAfter",
14152
14172
  template: "template",
14153
14173
  delegateEvents: "delegateEvents"
14154
14174
  };
@@ -14167,12 +14187,11 @@ var RUNTIME_ALIASES = {
14167
14187
  fragment: "Fragment",
14168
14188
  propGetter: "__fictProp",
14169
14189
  propsRest: "__fictPropsRest",
14170
- useProp: "useProp",
14190
+ prop: "prop",
14171
14191
  mergeProps: "mergeProps",
14172
14192
  runInScope: "runInScope",
14173
14193
  createElement: "createElement",
14174
14194
  conditional: "createConditional",
14175
- list: "createList",
14176
14195
  keyedList: "createKeyedList",
14177
14196
  insert: "insert",
14178
14197
  onDestroy: "onDestroy",
@@ -14185,38 +14204,10 @@ var RUNTIME_ALIASES = {
14185
14204
  callEventHandler: "callEventHandler",
14186
14205
  bindRef: "bindRef",
14187
14206
  toNodeArray: "toNodeArray",
14188
- createKeyedListContainer: "createKeyedListContainer",
14189
- createKeyedBlock: "createKeyedBlock",
14190
- moveMarkerBlock: "moveMarkerBlock",
14191
- destroyMarkerBlock: "destroyMarkerBlock",
14192
- getFirstNodeAfter: "getFirstNodeAfter",
14193
14207
  template: "template",
14194
14208
  delegateEvents: "delegateEvents"
14195
14209
  };
14196
- var DelegatedEvents = /* @__PURE__ */ new Set([
14197
- "beforeinput",
14198
- "click",
14199
- "dblclick",
14200
- "contextmenu",
14201
- "focusin",
14202
- "focusout",
14203
- "input",
14204
- "keydown",
14205
- "keyup",
14206
- "mousedown",
14207
- "mousemove",
14208
- "mouseout",
14209
- "mouseover",
14210
- "mouseup",
14211
- "pointerdown",
14212
- "pointermove",
14213
- "pointerout",
14214
- "pointerover",
14215
- "pointerup",
14216
- "touchend",
14217
- "touchmove",
14218
- "touchstart"
14219
- ]);
14210
+ var DelegatedEvents = /* @__PURE__ */ new Set([...DelegatedEventNames]);
14220
14211
  var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
14221
14212
  // Console methods
14222
14213
  "console.log",
@@ -14306,9 +14297,13 @@ var HIRError = class extends Error {
14306
14297
  }
14307
14298
  };
14308
14299
  var SSA_PATTERN = /\$\$ssa\d+$/;
14300
+ var GENERATED_SSA_NAMES = /* @__PURE__ */ new Set();
14309
14301
  function getSSABaseName(name) {
14310
14302
  if (name.startsWith("__")) return name;
14311
- return name.replace(SSA_PATTERN, "");
14303
+ if (GENERATED_SSA_NAMES.has(name)) {
14304
+ return name.replace(SSA_PATTERN, "");
14305
+ }
14306
+ return SSA_PATTERN.test(name) ? name : name;
14312
14307
  }
14313
14308
  function extractDependencyPath(expr) {
14314
14309
  if (expr.kind === "Identifier") {
@@ -16038,38 +16033,6 @@ function debugEnabled(flag) {
16038
16033
  return parts.includes(normalized) || parts.includes("all");
16039
16034
  }
16040
16035
 
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
16036
  // src/fine-grained-dom.ts
16074
16037
  function normalizeDependencyKey(name) {
16075
16038
  return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
@@ -16078,35 +16041,113 @@ function applyRegionMetadata(state, options) {
16078
16041
  if (!options.region) return;
16079
16042
  const region = options.region;
16080
16043
  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
- }
16044
+ if (region.dependencies.size === 0) return;
16045
+ const dependencyGetter = options.dependencyGetter;
16046
+ if (!dependencyGetter) return;
16047
+ state.identifierOverrides = state.identifierOverrides ?? {};
16048
+ for (const dep of region.dependencies) {
16049
+ const key = normalizeDependencyKey(dep);
16050
+ state.identifierOverrides[key] = () => dependencyGetter(dep);
16051
+ const base = key.split(".")[0];
16052
+ if (base && !state.identifierOverrides[base]) {
16053
+ state.identifierOverrides[base] = () => dependencyGetter(base);
16094
16054
  }
16095
16055
  }
16096
16056
  }
16097
16057
  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
- }
16058
+ if (region.dependencies.size > 0) return true;
16059
+ if (region.hasControlFlow) return true;
16060
+ if (region.hasReactiveWrites) return true;
16107
16061
  return false;
16108
16062
  }
16109
16063
 
16064
+ // src/validation.ts
16065
+ var DiagnosticMessages = {
16066
+ ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
16067
+ ["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
16068
+ ["FICT-P003" /* FICT_P003 */]: "Computed property in props pattern cannot be made reactive.",
16069
+ ["FICT-P004" /* FICT_P004 */]: "Nested props destructuring falls back to non-reactive binding; access props directly or use prop.",
16070
+ ["FICT-S001" /* FICT_S001 */]: "State variable mutation detected outside component scope.",
16071
+ ["FICT-S002" /* FICT_S002 */]: "State variable escaped to external scope, may cause memory leaks.",
16072
+ ["FICT-E001" /* FICT_E001 */]: "Effect without reactive dependencies will run only once; consider adding state reads or removing the effect.",
16073
+ ["FICT-E002" /* FICT_E002 */]: "Effect captures reactive value that may change.",
16074
+ ["FICT-E003" /* FICT_E003 */]: "Effect cleanup function is not properly tracked.",
16075
+ ["FICT-M001" /* FICT_M001 */]: "Memo has no reactive dependencies and could be a constant.",
16076
+ ["FICT-M002" /* FICT_M002 */]: "Unnecessary memo wrapping a constant value.",
16077
+ ["FICT-M003" /* FICT_M003 */]: "Memo should not contain side effects.",
16078
+ ["FICT-C001" /* FICT_C001 */]: "Hooks should not be called conditionally.",
16079
+ ["FICT-C002" /* FICT_C002 */]: "Hooks should not be called inside loops.",
16080
+ ["FICT-C003" /* FICT_C003 */]: "Components should not be defined inside other components.",
16081
+ ["FICT-C004" /* FICT_C004 */]: "Component has no return statement and will render nothing.",
16082
+ ["FICT-J001" /* FICT_J001 */]: "Dynamic key expression may impact performance.",
16083
+ ["FICT-J002" /* FICT_J002 */]: "Missing key prop in list rendering.",
16084
+ ["FICT-J003" /* FICT_J003 */]: "Spread on native element may include unknown props.",
16085
+ ["FICT-R001" /* FICT_R001 */]: "Expression crosses reactive region boundary.",
16086
+ ["FICT-R002" /* FICT_R002 */]: "Scope escape detected, value may not be tracked.",
16087
+ ["FICT-R003" /* FICT_R003 */]: "Expression cannot be memoized automatically.",
16088
+ ["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.",
16089
+ ["FICT-R005" /* FICT_R005 */]: "Function captures reactive variables from outer scope; pass them as parameters or memoize explicitly to avoid hidden dependencies.",
16090
+ ["FICT-X001" /* FICT_X001 */]: "Object is recreated on each render, consider memoizing.",
16091
+ ["FICT-X002" /* FICT_X002 */]: "Array is recreated on each render, consider memoizing.",
16092
+ ["FICT-X003" /* FICT_X003 */]: "Inline function in JSX props may cause unnecessary re-renders."
16093
+ };
16094
+ var DiagnosticSeverities = {
16095
+ ["FICT-P001" /* FICT_P001 */]: "warning" /* Warning */,
16096
+ ["FICT-P002" /* FICT_P002 */]: "warning" /* Warning */,
16097
+ ["FICT-P003" /* FICT_P003 */]: "warning" /* Warning */,
16098
+ ["FICT-P004" /* FICT_P004 */]: "warning" /* Warning */,
16099
+ ["FICT-S001" /* FICT_S001 */]: "error" /* Error */,
16100
+ ["FICT-S002" /* FICT_S002 */]: "warning" /* Warning */,
16101
+ ["FICT-E001" /* FICT_E001 */]: "warning" /* Warning */,
16102
+ ["FICT-E002" /* FICT_E002 */]: "info" /* Info */,
16103
+ ["FICT-E003" /* FICT_E003 */]: "warning" /* Warning */,
16104
+ ["FICT-M001" /* FICT_M001 */]: "info" /* Info */,
16105
+ ["FICT-M002" /* FICT_M002 */]: "hint" /* Hint */,
16106
+ ["FICT-M003" /* FICT_M003 */]: "error" /* Error */,
16107
+ ["FICT-C001" /* FICT_C001 */]: "error" /* Error */,
16108
+ ["FICT-C002" /* FICT_C002 */]: "error" /* Error */,
16109
+ ["FICT-C003" /* FICT_C003 */]: "warning" /* Warning */,
16110
+ ["FICT-C004" /* FICT_C004 */]: "warning" /* Warning */,
16111
+ ["FICT-J001" /* FICT_J001 */]: "info" /* Info */,
16112
+ ["FICT-J002" /* FICT_J002 */]: "warning" /* Warning */,
16113
+ ["FICT-J003" /* FICT_J003 */]: "info" /* Info */,
16114
+ ["FICT-R001" /* FICT_R001 */]: "info" /* Info */,
16115
+ ["FICT-R002" /* FICT_R002 */]: "warning" /* Warning */,
16116
+ ["FICT-R003" /* FICT_R003 */]: "info" /* Info */,
16117
+ ["FICT-R004" /* FICT_R004 */]: "warning" /* Warning */,
16118
+ ["FICT-R005" /* FICT_R005 */]: "warning" /* Warning */,
16119
+ ["FICT-X001" /* FICT_X001 */]: "hint" /* Hint */,
16120
+ ["FICT-X002" /* FICT_X002 */]: "hint" /* Hint */,
16121
+ ["FICT-X003" /* FICT_X003 */]: "hint" /* Hint */
16122
+ };
16123
+ function createDiagnostic(code, node, fileName, context) {
16124
+ const loc = node.loc;
16125
+ return {
16126
+ code,
16127
+ severity: DiagnosticSeverities[code],
16128
+ message: DiagnosticMessages[code],
16129
+ fileName,
16130
+ line: loc?.start.line ?? 0,
16131
+ column: loc?.start.column ?? 0,
16132
+ endLine: loc?.end.line,
16133
+ endColumn: loc?.end.column,
16134
+ context
16135
+ };
16136
+ }
16137
+ function reportDiagnostic(ctx, code, node, context) {
16138
+ const fileName = ctx.file?.opts?.filename || "<unknown>";
16139
+ const diagnostic = createDiagnostic(code, node, fileName, context);
16140
+ if (ctx.options?.onWarn) {
16141
+ ctx.options.onWarn({
16142
+ code: diagnostic.code,
16143
+ message: diagnostic.message,
16144
+ fileName: diagnostic.fileName,
16145
+ line: diagnostic.line,
16146
+ column: diagnostic.column
16147
+ });
16148
+ }
16149
+ }
16150
+
16110
16151
  // src/ir/ssa.ts
16111
16152
  function analyzeCFG(blocks) {
16112
16153
  const predecessors = computePredecessors(blocks);
@@ -19412,7 +19453,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19412
19453
  const isTracked = ctx.trackedVars.has(baseName2);
19413
19454
  const isSignal = ctx.signalVars?.has(baseName2) ?? false;
19414
19455
  const aliasVars = ctx.aliasVars ?? (ctx.aliasVars = /* @__PURE__ */ new Set());
19415
- const dependsOnTracked2 = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19456
+ const dependsOnTracked = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19416
19457
  const capturedTracked = ctx.externalTracked && ctx.externalTracked.has(baseName2) && !declaredVars.has(baseName2);
19417
19458
  const isShadowDeclaration = !!declKind && declaredVars.has(baseName2);
19418
19459
  const treatAsTracked = !isShadowDeclaration && isTracked;
@@ -19420,8 +19461,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19420
19461
  const isStateCall2 = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && instr.value.callee.name === "$state";
19421
19462
  const inRegionMemo = ctx.inRegionMemo ?? false;
19422
19463
  const isFunctionValue = instr.value.kind === "ArrowFunction" || instr.value.kind === "FunctionExpression";
19423
- const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "useProp"].includes(instr.value.callee.name);
19424
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
19464
+ const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "prop"].includes(instr.value.callee.name);
19465
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
19425
19466
  const isMemoReturningCall = isAccessorReturningCall || isReactiveObjectCall;
19426
19467
  const lowerAssignedValue = (forceAssigned = false) => lowerExpressionWithDeSSA(instr.value, ctx, forceAssigned || isFunctionValue);
19427
19468
  const buildMemoCall = (expr) => {
@@ -19443,10 +19484,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19443
19484
  ctx.trackedVars.delete(baseName2);
19444
19485
  }
19445
19486
  if (declKind) {
19446
- const normalizedDecl = isStateCall2 || dependsOnTracked2 && !isDestructuringTemp ? "const" : declKind;
19487
+ const normalizedDecl = isStateCall2 || dependsOnTracked && !isDestructuringTemp ? "const" : declKind;
19447
19488
  const needsMutable = ctx.mutatedVars?.has(baseName2) ?? false;
19448
19489
  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;
19490
+ const fallbackDecl = !treatAsTracked && (!dependsOnTracked || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
19450
19491
  declaredVars.add(baseName2);
19451
19492
  if (treatAsTracked && !isDestructuringTemp) {
19452
19493
  if (isStateCall2) {
@@ -19454,7 +19495,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19454
19495
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19455
19496
  ]);
19456
19497
  }
19457
- if (dependsOnTracked2) {
19498
+ if (dependsOnTracked) {
19458
19499
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19459
19500
  aliasVars.add(baseName2);
19460
19501
  }
@@ -19481,7 +19522,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19481
19522
  ]);
19482
19523
  }
19483
19524
  }
19484
- if (dependsOnTracked2 && !isDestructuringTemp) {
19525
+ if (dependsOnTracked && !isDestructuringTemp) {
19485
19526
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19486
19527
  aliasVars.add(baseName2);
19487
19528
  }
@@ -19522,7 +19563,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19522
19563
  if (aliasVars.has(baseName2) && !declaredVars.has(baseName2)) {
19523
19564
  throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
19524
19565
  }
19525
- if (dependsOnTracked2 && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19566
+ if (dependsOnTracked && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19526
19567
  const derivedExpr = lowerAssignedValue(true);
19527
19568
  aliasVars.add(baseName2);
19528
19569
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
@@ -19573,7 +19614,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19573
19614
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19574
19615
  ]);
19575
19616
  }
19576
- if (dependsOnTracked2) {
19617
+ if (dependsOnTracked) {
19577
19618
  const derivedExpr = lowerAssignedValue(true);
19578
19619
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19579
19620
  return t2.variableDeclaration("const", [
@@ -19600,7 +19641,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19600
19641
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19601
19642
  ]);
19602
19643
  }
19603
- if (dependsOnTracked2) {
19644
+ if (dependsOnTracked) {
19604
19645
  const derivedExpr = lowerAssignedValue(true);
19605
19646
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19606
19647
  return t2.variableDeclaration("let", [
@@ -21055,7 +21096,7 @@ function computeReactiveAccessors(fn, ctx) {
21055
21096
  tracked.add(target);
21056
21097
  changed = true;
21057
21098
  }
21058
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
21099
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
21059
21100
  if (hasDataDep && !isSignal(target) && !isStore(target) && !isReactiveObjectCall) {
21060
21101
  memo.add(target);
21061
21102
  }
@@ -21678,8 +21719,8 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21678
21719
  const shouldMemoProp = usesTracked && !t2.isIdentifier(valueExprRaw) && !t2.isMemberExpression(valueExprRaw) && !t2.isLiteral(valueExprRaw);
21679
21720
  const valueExpr = usesTracked && ctx.t.isExpression(valueExprRaw) ? (() => {
21680
21721
  if (shouldMemoProp) {
21681
- ctx.helpersUsed.add("useProp");
21682
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
21722
+ ctx.helpersUsed.add("prop");
21723
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
21683
21724
  t2.arrowFunctionExpression([], valueExprRaw)
21684
21725
  ]);
21685
21726
  }
@@ -22245,6 +22286,9 @@ function applyRegionMetadataToExpression(expr, ctx, regionOverride, options) {
22245
22286
  }
22246
22287
  function replaceIdentifiersWithOverrides(node, overrides, t2, parentKind, parentKey, skipCurrentNode = false) {
22247
22288
  const isCallTarget = parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
22289
+ if (parentKind === "VariableDeclarator" && parentKey === "id") {
22290
+ return;
22291
+ }
22248
22292
  const collectParamNames = (params) => {
22249
22293
  const names = /* @__PURE__ */ new Set();
22250
22294
  const addName = (n) => {
@@ -23611,7 +23655,7 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23611
23655
  if (isKeyed) {
23612
23656
  ctx.helpersUsed.add("keyedList");
23613
23657
  } else {
23614
- ctx.helpersUsed.add("list");
23658
+ ctx.helpersUsed.add("keyedList");
23615
23659
  ctx.helpersUsed.add("createElement");
23616
23660
  }
23617
23661
  const prevHoistedTemplates = ctx.hoistedTemplates;
@@ -23652,6 +23696,17 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23652
23696
  overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
23653
23697
  }
23654
23698
  if (Object.keys(overrides).length > 0) {
23699
+ if (t2.isBlockStatement(callbackExpr.body)) {
23700
+ for (const stmt of callbackExpr.body.body) {
23701
+ if (!t2.isVariableDeclaration(stmt)) continue;
23702
+ for (const decl of stmt.declarations) {
23703
+ if (!t2.isIdentifier(decl.id) || !decl.init) continue;
23704
+ const replacement = t2.cloneNode(decl.init, true);
23705
+ replaceIdentifiersWithOverrides(replacement, overrides, t2, callbackExpr.type, "body");
23706
+ overrides[decl.id.name] = () => t2.cloneNode(replacement, true);
23707
+ }
23708
+ }
23709
+ }
23655
23710
  if (t2.isBlockStatement(callbackExpr.body)) {
23656
23711
  replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
23657
23712
  } else {
@@ -23730,14 +23785,22 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23730
23785
  );
23731
23786
  } else {
23732
23787
  statements.push(...hoistedStatements);
23788
+ const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : "__item" : "__item";
23789
+ const indexParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[1]) ? callbackExpr.params[1].name : "__index" : "__index";
23790
+ const hasIndexParam = (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
23791
+ const keyFn = t2.arrowFunctionExpression(
23792
+ [t2.identifier(itemParamName), t2.identifier(indexParamName)],
23793
+ t2.identifier(indexParamName)
23794
+ );
23733
23795
  statements.push(
23734
23796
  t2.variableDeclaration("const", [
23735
23797
  t2.variableDeclarator(
23736
23798
  listId,
23737
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.list), [
23799
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.keyedList), [
23738
23800
  t2.arrowFunctionExpression([], arrayExpr),
23801
+ keyFn,
23739
23802
  callbackExpr,
23740
- t2.identifier(RUNTIME_ALIASES.createElement)
23803
+ t2.booleanLiteral(hasIndexParam)
23741
23804
  ])
23742
23805
  )
23743
23806
  ])
@@ -23857,8 +23920,8 @@ function buildPropsObject(attributes, ctx) {
23857
23920
  ]);
23858
23921
  })() : usesTracked && t2.isExpression(lowered) ? (() => {
23859
23922
  if (useMemoProp) {
23860
- ctx.helpersUsed.add("useProp");
23861
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
23923
+ ctx.helpersUsed.add("prop");
23924
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
23862
23925
  t2.arrowFunctionExpression(
23863
23926
  [],
23864
23927
  trackedExpr ?? lowered
@@ -24380,61 +24443,100 @@ function lowerFunctionWithRegions(fn, ctx) {
24380
24443
  const stmts = [];
24381
24444
  const excludeKeys = [];
24382
24445
  let supported = true;
24383
- let usesUseProp = false;
24446
+ let usesProp = false;
24384
24447
  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)) {
24448
+ let warnedNested = false;
24449
+ const memberExprForKey = (base, key) => t2.memberExpression(base, t2.identifier(key), false);
24450
+ const buildDestructure = (objectPattern, baseExpr, allowRest) => {
24451
+ for (const prop of objectPattern.properties) {
24452
+ if (t2.isObjectProperty(prop) && !prop.computed) {
24453
+ 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;
24454
+ if (!keyName) {
24455
+ reportDiagnostic(ctx, "FICT-P003" /* FICT_P003 */, prop);
24456
+ supported = false;
24457
+ warnedNested = true;
24458
+ break;
24459
+ }
24460
+ if (allowRest) {
24461
+ excludeKeys.push(t2.stringLiteral(keyName));
24462
+ }
24463
+ const member = memberExprForKey(baseExpr, keyName);
24464
+ const value = prop.value;
24465
+ if (t2.isIdentifier(value)) {
24466
+ const shouldWrapProp = !calledIdentifiers.has(value.name);
24467
+ if (shouldWrapProp) {
24468
+ usesProp = true;
24469
+ propsPlanAliases.add(value.name);
24470
+ }
24471
+ stmts.push(
24472
+ t2.variableDeclaration("const", [
24473
+ t2.variableDeclarator(
24474
+ t2.identifier(value.name),
24475
+ shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24476
+ t2.arrowFunctionExpression([], member)
24477
+ ]) : member
24478
+ )
24479
+ ])
24480
+ );
24481
+ continue;
24482
+ }
24483
+ if (t2.isObjectPattern(value)) {
24484
+ buildDestructure(value, member, false);
24485
+ if (!supported) break;
24486
+ continue;
24487
+ }
24488
+ if (t2.isAssignmentPattern(value) && t2.isIdentifier(value.left)) {
24489
+ const shouldWrapProp = !calledIdentifiers.has(value.left.name);
24490
+ if (shouldWrapProp) {
24491
+ usesProp = true;
24492
+ propsPlanAliases.add(value.left.name);
24493
+ }
24494
+ const baseInit = t2.logicalExpression("??", member, value.right);
24495
+ const init = shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24496
+ t2.arrowFunctionExpression([], baseInit)
24497
+ ]) : baseInit;
24498
+ stmts.push(
24499
+ t2.variableDeclaration("const", [
24500
+ t2.variableDeclarator(t2.identifier(value.left.name), init)
24501
+ ])
24502
+ );
24503
+ continue;
24504
+ }
24389
24505
  supported = false;
24506
+ if (!warnedNested) {
24507
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24508
+ warnedNested = true;
24509
+ }
24390
24510
  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);
24511
+ } else if (t2.isRestElement(prop) && allowRest && t2.isIdentifier(prop.argument)) {
24512
+ usesPropsRest = true;
24397
24513
  stmts.push(
24398
24514
  t2.variableDeclaration("const", [
24399
24515
  t2.variableDeclarator(
24400
- t2.identifier(prop.value.name),
24401
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24402
- t2.arrowFunctionExpression([], member)
24516
+ t2.identifier(prop.argument.name),
24517
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), [
24518
+ baseExpr,
24519
+ t2.arrayExpression(excludeKeys)
24403
24520
  ])
24404
24521
  )
24405
24522
  ])
24406
24523
  );
24524
+ continue;
24407
24525
  } else {
24408
- stmts.push(
24409
- t2.variableDeclaration("const", [
24410
- t2.variableDeclarator(t2.identifier(prop.value.name), member)
24411
- ])
24412
- );
24526
+ supported = false;
24527
+ if (!warnedNested) {
24528
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24529
+ warnedNested = true;
24530
+ }
24531
+ break;
24413
24532
  }
24414
- continue;
24415
- }
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
24533
  }
24431
- supported = false;
24432
- break;
24433
- }
24534
+ };
24535
+ buildDestructure(pattern, t2.identifier("__props"), true);
24434
24536
  if (supported) {
24435
24537
  propsDestructurePlan = {
24436
24538
  statements: stmts,
24437
- usesUseProp,
24539
+ usesProp,
24438
24540
  usesPropsRest
24439
24541
  };
24440
24542
  propsPlanAliases.forEach((name) => {
@@ -24528,8 +24630,8 @@ function lowerFunctionWithRegions(fn, ctx) {
24528
24630
  finalParams = [t2.identifier("__props")];
24529
24631
  const pattern = rawParam.type === "AssignmentPattern" ? rawParam.left : rawParam;
24530
24632
  if (propsDestructurePlan) {
24531
- if (propsDestructurePlan.usesUseProp) {
24532
- ctx.helpersUsed.add("useProp");
24633
+ if (propsDestructurePlan.usesProp) {
24634
+ ctx.helpersUsed.add("prop");
24533
24635
  }
24534
24636
  if (propsDestructurePlan.usesPropsRest) {
24535
24637
  ctx.helpersUsed.add("propsRest");
@@ -24598,6 +24700,38 @@ function flattenRegions(regions) {
24598
24700
  });
24599
24701
  }
24600
24702
 
24703
+ // src/utils.ts
24704
+ function isStateCall(node, t2) {
24705
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
24706
+ }
24707
+ function isEffectCall(node, t2) {
24708
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
24709
+ }
24710
+ function getRootIdentifier(expr, t2) {
24711
+ if (t2.isIdentifier(expr)) {
24712
+ return expr;
24713
+ }
24714
+ if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
24715
+ return getRootIdentifier(expr.object, t2);
24716
+ }
24717
+ if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
24718
+ return getRootIdentifier(expr.object, t2);
24719
+ }
24720
+ if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
24721
+ return getRootIdentifier(expr.callee, t2);
24722
+ }
24723
+ if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
24724
+ return getRootIdentifier(expr.callee, t2);
24725
+ }
24726
+ if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
24727
+ return getRootIdentifier(expr.expression, t2);
24728
+ }
24729
+ if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
24730
+ return getRootIdentifier(expr.expression, t2);
24731
+ }
24732
+ return null;
24733
+ }
24734
+
24601
24735
  // src/index.ts
24602
24736
  function stripMacroImports(path, t2) {
24603
24737
  path.traverse({
@@ -24985,8 +25119,10 @@ function createHIREntrypointVisitor(t2, options) {
24985
25119
  const fileName = path.hub?.file?.opts?.filename || "<unknown>";
24986
25120
  const comments = path.hub?.file?.ast?.comments || [];
24987
25121
  const suppressions = parseSuppressions(comments);
24988
- const warn = createWarningDispatcher(options.onWarn, suppressions);
24989
- const optionsWithWarnings = { ...options, onWarn: warn };
25122
+ const dev = options.dev !== false;
25123
+ const warn = dev ? createWarningDispatcher(options.onWarn, suppressions) : () => {
25124
+ };
25125
+ const optionsWithWarnings = dev ? { ...options, onWarn: warn } : { ...options, onWarn: void 0 };
24990
25126
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
24991
25127
  const getFunctionName = (fnPath) => {
24992
25128
  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;
@@ -25242,6 +25378,18 @@ function createHIREntrypointVisitor(t2, options) {
25242
25378
  },
25243
25379
  CallExpression(callPath) {
25244
25380
  if (isStateCall(callPath.node, t2)) {
25381
+ const parentPath = callPath.parentPath;
25382
+ const isVariableDeclarator = parentPath?.isVariableDeclarator() && parentPath.node.init === callPath.node;
25383
+ if (!isVariableDeclarator) {
25384
+ throw callPath.buildCodeFrameError(
25385
+ "$state() must be assigned directly to a variable (e.g. let count = $state(0)). For object state, consider using $store from fict/plus."
25386
+ );
25387
+ }
25388
+ if (!t2.isIdentifier(parentPath.node.id)) {
25389
+ throw callPath.buildCodeFrameError(
25390
+ "Destructuring $state is not supported. Use a simple identifier."
25391
+ );
25392
+ }
25245
25393
  const ownerComponent = callPath.getFunctionParent();
25246
25394
  if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
25247
25395
  throw callPath.buildCodeFrameError(
@@ -25434,7 +25582,9 @@ function createHIREntrypointVisitor(t2, options) {
25434
25582
  }
25435
25583
  });
25436
25584
  }
25437
- runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25585
+ if (dev) {
25586
+ runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25587
+ }
25438
25588
  const fileAst = t2.file(path.node);
25439
25589
  const hir = buildHIR(fileAst);
25440
25590
  const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
@@ -25454,7 +25604,8 @@ var createFictPlugin = declare(
25454
25604
  const t2 = api.types;
25455
25605
  const normalizedOptions = {
25456
25606
  ...options,
25457
- fineGrainedDom: options.fineGrainedDom ?? true
25607
+ fineGrainedDom: options.fineGrainedDom ?? true,
25608
+ dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
25458
25609
  };
25459
25610
  return {
25460
25611
  name: "fict-compiler-hir",