@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.cjs CHANGED
@@ -14121,8 +14121,34 @@ __export(index_exports, {
14121
14121
  module.exports = __toCommonJS(index_exports);
14122
14122
  var import_helper_plugin_utils = require("@babel/helper-plugin-utils");
14123
14123
 
14124
+ // ../runtime/src/delegated-events.ts
14125
+ var DelegatedEventNames = [
14126
+ "beforeinput",
14127
+ "click",
14128
+ "dblclick",
14129
+ "contextmenu",
14130
+ "focusin",
14131
+ "focusout",
14132
+ "input",
14133
+ "keydown",
14134
+ "keyup",
14135
+ "mousedown",
14136
+ "mousemove",
14137
+ "mouseout",
14138
+ "mouseover",
14139
+ "mouseup",
14140
+ "pointerdown",
14141
+ "pointermove",
14142
+ "pointerout",
14143
+ "pointerover",
14144
+ "pointerup",
14145
+ "touchend",
14146
+ "touchmove",
14147
+ "touchstart"
14148
+ ];
14149
+
14124
14150
  // src/constants.ts
14125
- var RUNTIME_MODULE = "@fictjs/runtime";
14151
+ var RUNTIME_MODULE = "@fictjs/runtime/internal";
14126
14152
  var RUNTIME_HELPERS = {
14127
14153
  signal: "createSignal",
14128
14154
  createSelector: "createSelector",
@@ -14139,11 +14165,10 @@ var RUNTIME_HELPERS = {
14139
14165
  propGetter: "__fictProp",
14140
14166
  propsRest: "__fictPropsRest",
14141
14167
  mergeProps: "mergeProps",
14142
- useProp: "useProp",
14168
+ prop: "prop",
14143
14169
  runInScope: "runInScope",
14144
14170
  createElement: "createElement",
14145
14171
  conditional: "createConditional",
14146
- list: "createList",
14147
14172
  keyedList: "createKeyedList",
14148
14173
  insert: "insert",
14149
14174
  onDestroy: "onDestroy",
@@ -14156,11 +14181,6 @@ var RUNTIME_HELPERS = {
14156
14181
  callEventHandler: "callEventHandler",
14157
14182
  bindRef: "bindRef",
14158
14183
  toNodeArray: "toNodeArray",
14159
- createKeyedListContainer: "createKeyedListContainer",
14160
- createKeyedBlock: "createKeyedBlock",
14161
- moveMarkerBlock: "moveMarkerBlock",
14162
- destroyMarkerBlock: "destroyMarkerBlock",
14163
- getFirstNodeAfter: "getFirstNodeAfter",
14164
14184
  template: "template",
14165
14185
  delegateEvents: "delegateEvents"
14166
14186
  };
@@ -14179,12 +14199,11 @@ var RUNTIME_ALIASES = {
14179
14199
  fragment: "Fragment",
14180
14200
  propGetter: "__fictProp",
14181
14201
  propsRest: "__fictPropsRest",
14182
- useProp: "useProp",
14202
+ prop: "prop",
14183
14203
  mergeProps: "mergeProps",
14184
14204
  runInScope: "runInScope",
14185
14205
  createElement: "createElement",
14186
14206
  conditional: "createConditional",
14187
- list: "createList",
14188
14207
  keyedList: "createKeyedList",
14189
14208
  insert: "insert",
14190
14209
  onDestroy: "onDestroy",
@@ -14197,38 +14216,10 @@ var RUNTIME_ALIASES = {
14197
14216
  callEventHandler: "callEventHandler",
14198
14217
  bindRef: "bindRef",
14199
14218
  toNodeArray: "toNodeArray",
14200
- createKeyedListContainer: "createKeyedListContainer",
14201
- createKeyedBlock: "createKeyedBlock",
14202
- moveMarkerBlock: "moveMarkerBlock",
14203
- destroyMarkerBlock: "destroyMarkerBlock",
14204
- getFirstNodeAfter: "getFirstNodeAfter",
14205
14219
  template: "template",
14206
14220
  delegateEvents: "delegateEvents"
14207
14221
  };
14208
- var DelegatedEvents = /* @__PURE__ */ new Set([
14209
- "beforeinput",
14210
- "click",
14211
- "dblclick",
14212
- "contextmenu",
14213
- "focusin",
14214
- "focusout",
14215
- "input",
14216
- "keydown",
14217
- "keyup",
14218
- "mousedown",
14219
- "mousemove",
14220
- "mouseout",
14221
- "mouseover",
14222
- "mouseup",
14223
- "pointerdown",
14224
- "pointermove",
14225
- "pointerout",
14226
- "pointerover",
14227
- "pointerup",
14228
- "touchend",
14229
- "touchmove",
14230
- "touchstart"
14231
- ]);
14222
+ var DelegatedEvents = /* @__PURE__ */ new Set([...DelegatedEventNames]);
14232
14223
  var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
14233
14224
  // Console methods
14234
14225
  "console.log",
@@ -14318,9 +14309,13 @@ var HIRError = class extends Error {
14318
14309
  }
14319
14310
  };
14320
14311
  var SSA_PATTERN = /\$\$ssa\d+$/;
14312
+ var GENERATED_SSA_NAMES = /* @__PURE__ */ new Set();
14321
14313
  function getSSABaseName(name) {
14322
14314
  if (name.startsWith("__")) return name;
14323
- return name.replace(SSA_PATTERN, "");
14315
+ if (GENERATED_SSA_NAMES.has(name)) {
14316
+ return name.replace(SSA_PATTERN, "");
14317
+ }
14318
+ return SSA_PATTERN.test(name) ? name : name;
14324
14319
  }
14325
14320
  function extractDependencyPath(expr) {
14326
14321
  if (expr.kind === "Identifier") {
@@ -16050,38 +16045,6 @@ function debugEnabled(flag) {
16050
16045
  return parts.includes(normalized) || parts.includes("all");
16051
16046
  }
16052
16047
 
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
16048
  // src/fine-grained-dom.ts
16086
16049
  function normalizeDependencyKey(name) {
16087
16050
  return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
@@ -16090,35 +16053,113 @@ function applyRegionMetadata(state, options) {
16090
16053
  if (!options.region) return;
16091
16054
  const region = options.region;
16092
16055
  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
- }
16056
+ if (region.dependencies.size === 0) return;
16057
+ const dependencyGetter = options.dependencyGetter;
16058
+ if (!dependencyGetter) return;
16059
+ state.identifierOverrides = state.identifierOverrides ?? {};
16060
+ for (const dep of region.dependencies) {
16061
+ const key = normalizeDependencyKey(dep);
16062
+ state.identifierOverrides[key] = () => dependencyGetter(dep);
16063
+ const base = key.split(".")[0];
16064
+ if (base && !state.identifierOverrides[base]) {
16065
+ state.identifierOverrides[base] = () => dependencyGetter(base);
16106
16066
  }
16107
16067
  }
16108
16068
  }
16109
16069
  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
- }
16070
+ if (region.dependencies.size > 0) return true;
16071
+ if (region.hasControlFlow) return true;
16072
+ if (region.hasReactiveWrites) return true;
16119
16073
  return false;
16120
16074
  }
16121
16075
 
16076
+ // src/validation.ts
16077
+ var DiagnosticMessages = {
16078
+ ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
16079
+ ["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
16080
+ ["FICT-P003" /* FICT_P003 */]: "Computed property in props pattern cannot be made reactive.",
16081
+ ["FICT-P004" /* FICT_P004 */]: "Nested props destructuring falls back to non-reactive binding; access props directly or use prop.",
16082
+ ["FICT-S001" /* FICT_S001 */]: "State variable mutation detected outside component scope.",
16083
+ ["FICT-S002" /* FICT_S002 */]: "State variable escaped to external scope, may cause memory leaks.",
16084
+ ["FICT-E001" /* FICT_E001 */]: "Effect without reactive dependencies will run only once; consider adding state reads or removing the effect.",
16085
+ ["FICT-E002" /* FICT_E002 */]: "Effect captures reactive value that may change.",
16086
+ ["FICT-E003" /* FICT_E003 */]: "Effect cleanup function is not properly tracked.",
16087
+ ["FICT-M001" /* FICT_M001 */]: "Memo has no reactive dependencies and could be a constant.",
16088
+ ["FICT-M002" /* FICT_M002 */]: "Unnecessary memo wrapping a constant value.",
16089
+ ["FICT-M003" /* FICT_M003 */]: "Memo should not contain side effects.",
16090
+ ["FICT-C001" /* FICT_C001 */]: "Hooks should not be called conditionally.",
16091
+ ["FICT-C002" /* FICT_C002 */]: "Hooks should not be called inside loops.",
16092
+ ["FICT-C003" /* FICT_C003 */]: "Components should not be defined inside other components.",
16093
+ ["FICT-C004" /* FICT_C004 */]: "Component has no return statement and will render nothing.",
16094
+ ["FICT-J001" /* FICT_J001 */]: "Dynamic key expression may impact performance.",
16095
+ ["FICT-J002" /* FICT_J002 */]: "Missing key prop in list rendering.",
16096
+ ["FICT-J003" /* FICT_J003 */]: "Spread on native element may include unknown props.",
16097
+ ["FICT-R001" /* FICT_R001 */]: "Expression crosses reactive region boundary.",
16098
+ ["FICT-R002" /* FICT_R002 */]: "Scope escape detected, value may not be tracked.",
16099
+ ["FICT-R003" /* FICT_R003 */]: "Expression cannot be memoized automatically.",
16100
+ ["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.",
16101
+ ["FICT-R005" /* FICT_R005 */]: "Function captures reactive variables from outer scope; pass them as parameters or memoize explicitly to avoid hidden dependencies.",
16102
+ ["FICT-X001" /* FICT_X001 */]: "Object is recreated on each render, consider memoizing.",
16103
+ ["FICT-X002" /* FICT_X002 */]: "Array is recreated on each render, consider memoizing.",
16104
+ ["FICT-X003" /* FICT_X003 */]: "Inline function in JSX props may cause unnecessary re-renders."
16105
+ };
16106
+ var DiagnosticSeverities = {
16107
+ ["FICT-P001" /* FICT_P001 */]: "warning" /* Warning */,
16108
+ ["FICT-P002" /* FICT_P002 */]: "warning" /* Warning */,
16109
+ ["FICT-P003" /* FICT_P003 */]: "warning" /* Warning */,
16110
+ ["FICT-P004" /* FICT_P004 */]: "warning" /* Warning */,
16111
+ ["FICT-S001" /* FICT_S001 */]: "error" /* Error */,
16112
+ ["FICT-S002" /* FICT_S002 */]: "warning" /* Warning */,
16113
+ ["FICT-E001" /* FICT_E001 */]: "warning" /* Warning */,
16114
+ ["FICT-E002" /* FICT_E002 */]: "info" /* Info */,
16115
+ ["FICT-E003" /* FICT_E003 */]: "warning" /* Warning */,
16116
+ ["FICT-M001" /* FICT_M001 */]: "info" /* Info */,
16117
+ ["FICT-M002" /* FICT_M002 */]: "hint" /* Hint */,
16118
+ ["FICT-M003" /* FICT_M003 */]: "error" /* Error */,
16119
+ ["FICT-C001" /* FICT_C001 */]: "error" /* Error */,
16120
+ ["FICT-C002" /* FICT_C002 */]: "error" /* Error */,
16121
+ ["FICT-C003" /* FICT_C003 */]: "warning" /* Warning */,
16122
+ ["FICT-C004" /* FICT_C004 */]: "warning" /* Warning */,
16123
+ ["FICT-J001" /* FICT_J001 */]: "info" /* Info */,
16124
+ ["FICT-J002" /* FICT_J002 */]: "warning" /* Warning */,
16125
+ ["FICT-J003" /* FICT_J003 */]: "info" /* Info */,
16126
+ ["FICT-R001" /* FICT_R001 */]: "info" /* Info */,
16127
+ ["FICT-R002" /* FICT_R002 */]: "warning" /* Warning */,
16128
+ ["FICT-R003" /* FICT_R003 */]: "info" /* Info */,
16129
+ ["FICT-R004" /* FICT_R004 */]: "warning" /* Warning */,
16130
+ ["FICT-R005" /* FICT_R005 */]: "warning" /* Warning */,
16131
+ ["FICT-X001" /* FICT_X001 */]: "hint" /* Hint */,
16132
+ ["FICT-X002" /* FICT_X002 */]: "hint" /* Hint */,
16133
+ ["FICT-X003" /* FICT_X003 */]: "hint" /* Hint */
16134
+ };
16135
+ function createDiagnostic(code, node, fileName, context) {
16136
+ const loc = node.loc;
16137
+ return {
16138
+ code,
16139
+ severity: DiagnosticSeverities[code],
16140
+ message: DiagnosticMessages[code],
16141
+ fileName,
16142
+ line: loc?.start.line ?? 0,
16143
+ column: loc?.start.column ?? 0,
16144
+ endLine: loc?.end.line,
16145
+ endColumn: loc?.end.column,
16146
+ context
16147
+ };
16148
+ }
16149
+ function reportDiagnostic(ctx, code, node, context) {
16150
+ const fileName = ctx.file?.opts?.filename || "<unknown>";
16151
+ const diagnostic = createDiagnostic(code, node, fileName, context);
16152
+ if (ctx.options?.onWarn) {
16153
+ ctx.options.onWarn({
16154
+ code: diagnostic.code,
16155
+ message: diagnostic.message,
16156
+ fileName: diagnostic.fileName,
16157
+ line: diagnostic.line,
16158
+ column: diagnostic.column
16159
+ });
16160
+ }
16161
+ }
16162
+
16122
16163
  // src/ir/ssa.ts
16123
16164
  function analyzeCFG(blocks) {
16124
16165
  const predecessors = computePredecessors(blocks);
@@ -19424,7 +19465,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19424
19465
  const isTracked = ctx.trackedVars.has(baseName2);
19425
19466
  const isSignal = ctx.signalVars?.has(baseName2) ?? false;
19426
19467
  const aliasVars = ctx.aliasVars ?? (ctx.aliasVars = /* @__PURE__ */ new Set());
19427
- const dependsOnTracked2 = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19468
+ const dependsOnTracked = expressionUsesTracked(instr.value, ctx) || (ctx.memoVars?.has(baseName2) ?? false);
19428
19469
  const capturedTracked = ctx.externalTracked && ctx.externalTracked.has(baseName2) && !declaredVars.has(baseName2);
19429
19470
  const isShadowDeclaration = !!declKind && declaredVars.has(baseName2);
19430
19471
  const treatAsTracked = !isShadowDeclaration && isTracked;
@@ -19432,8 +19473,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19432
19473
  const isStateCall2 = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && instr.value.callee.name === "$state";
19433
19474
  const inRegionMemo = ctx.inRegionMemo ?? false;
19434
19475
  const isFunctionValue = instr.value.kind === "ArrowFunction" || instr.value.kind === "FunctionExpression";
19435
- const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "useProp"].includes(instr.value.callee.name);
19436
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
19476
+ const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "prop"].includes(instr.value.callee.name);
19477
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
19437
19478
  const isMemoReturningCall = isAccessorReturningCall || isReactiveObjectCall;
19438
19479
  const lowerAssignedValue = (forceAssigned = false) => lowerExpressionWithDeSSA(instr.value, ctx, forceAssigned || isFunctionValue);
19439
19480
  const buildMemoCall = (expr) => {
@@ -19455,10 +19496,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19455
19496
  ctx.trackedVars.delete(baseName2);
19456
19497
  }
19457
19498
  if (declKind) {
19458
- const normalizedDecl = isStateCall2 || dependsOnTracked2 && !isDestructuringTemp ? "const" : declKind;
19499
+ const normalizedDecl = isStateCall2 || dependsOnTracked && !isDestructuringTemp ? "const" : declKind;
19459
19500
  const needsMutable = ctx.mutatedVars?.has(baseName2) ?? false;
19460
19501
  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;
19502
+ const fallbackDecl = !treatAsTracked && (!dependsOnTracked || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
19462
19503
  declaredVars.add(baseName2);
19463
19504
  if (treatAsTracked && !isDestructuringTemp) {
19464
19505
  if (isStateCall2) {
@@ -19466,7 +19507,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19466
19507
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19467
19508
  ]);
19468
19509
  }
19469
- if (dependsOnTracked2) {
19510
+ if (dependsOnTracked) {
19470
19511
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19471
19512
  aliasVars.add(baseName2);
19472
19513
  }
@@ -19493,7 +19534,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19493
19534
  ]);
19494
19535
  }
19495
19536
  }
19496
- if (dependsOnTracked2 && !isDestructuringTemp) {
19537
+ if (dependsOnTracked && !isDestructuringTemp) {
19497
19538
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
19498
19539
  aliasVars.add(baseName2);
19499
19540
  }
@@ -19534,7 +19575,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19534
19575
  if (aliasVars.has(baseName2) && !declaredVars.has(baseName2)) {
19535
19576
  throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
19536
19577
  }
19537
- if (dependsOnTracked2 && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19578
+ if (dependsOnTracked && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
19538
19579
  const derivedExpr = lowerAssignedValue(true);
19539
19580
  aliasVars.add(baseName2);
19540
19581
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
@@ -19585,7 +19626,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19585
19626
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19586
19627
  ]);
19587
19628
  }
19588
- if (dependsOnTracked2) {
19629
+ if (dependsOnTracked) {
19589
19630
  const derivedExpr = lowerAssignedValue(true);
19590
19631
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19591
19632
  return t2.variableDeclaration("const", [
@@ -19612,7 +19653,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19612
19653
  t2.variableDeclarator(t2.identifier(baseName2), lowerAssignedValue(true))
19613
19654
  ]);
19614
19655
  }
19615
- if (dependsOnTracked2) {
19656
+ if (dependsOnTracked) {
19616
19657
  const derivedExpr = lowerAssignedValue(true);
19617
19658
  if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
19618
19659
  return t2.variableDeclaration("let", [
@@ -21067,7 +21108,7 @@ function computeReactiveAccessors(fn, ctx) {
21067
21108
  tracked.add(target);
21068
21109
  changed = true;
21069
21110
  }
21070
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
21111
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
21071
21112
  if (hasDataDep && !isSignal(target) && !isStore(target) && !isReactiveObjectCall) {
21072
21113
  memo.add(target);
21073
21114
  }
@@ -21690,8 +21731,8 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21690
21731
  const shouldMemoProp = usesTracked && !t2.isIdentifier(valueExprRaw) && !t2.isMemberExpression(valueExprRaw) && !t2.isLiteral(valueExprRaw);
21691
21732
  const valueExpr = usesTracked && ctx.t.isExpression(valueExprRaw) ? (() => {
21692
21733
  if (shouldMemoProp) {
21693
- ctx.helpersUsed.add("useProp");
21694
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
21734
+ ctx.helpersUsed.add("prop");
21735
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
21695
21736
  t2.arrowFunctionExpression([], valueExprRaw)
21696
21737
  ]);
21697
21738
  }
@@ -22257,6 +22298,9 @@ function applyRegionMetadataToExpression(expr, ctx, regionOverride, options) {
22257
22298
  }
22258
22299
  function replaceIdentifiersWithOverrides(node, overrides, t2, parentKind, parentKey, skipCurrentNode = false) {
22259
22300
  const isCallTarget = parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
22301
+ if (parentKind === "VariableDeclarator" && parentKey === "id") {
22302
+ return;
22303
+ }
22260
22304
  const collectParamNames = (params) => {
22261
22305
  const names = /* @__PURE__ */ new Set();
22262
22306
  const addName = (n) => {
@@ -23623,7 +23667,7 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23623
23667
  if (isKeyed) {
23624
23668
  ctx.helpersUsed.add("keyedList");
23625
23669
  } else {
23626
- ctx.helpersUsed.add("list");
23670
+ ctx.helpersUsed.add("keyedList");
23627
23671
  ctx.helpersUsed.add("createElement");
23628
23672
  }
23629
23673
  const prevHoistedTemplates = ctx.hoistedTemplates;
@@ -23664,6 +23708,17 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23664
23708
  overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
23665
23709
  }
23666
23710
  if (Object.keys(overrides).length > 0) {
23711
+ if (t2.isBlockStatement(callbackExpr.body)) {
23712
+ for (const stmt of callbackExpr.body.body) {
23713
+ if (!t2.isVariableDeclaration(stmt)) continue;
23714
+ for (const decl of stmt.declarations) {
23715
+ if (!t2.isIdentifier(decl.id) || !decl.init) continue;
23716
+ const replacement = t2.cloneNode(decl.init, true);
23717
+ replaceIdentifiersWithOverrides(replacement, overrides, t2, callbackExpr.type, "body");
23718
+ overrides[decl.id.name] = () => t2.cloneNode(replacement, true);
23719
+ }
23720
+ }
23721
+ }
23667
23722
  if (t2.isBlockStatement(callbackExpr.body)) {
23668
23723
  replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
23669
23724
  } else {
@@ -23742,14 +23797,22 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
23742
23797
  );
23743
23798
  } else {
23744
23799
  statements.push(...hoistedStatements);
23800
+ const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : "__item" : "__item";
23801
+ const indexParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[1]) ? callbackExpr.params[1].name : "__index" : "__index";
23802
+ const hasIndexParam = (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
23803
+ const keyFn = t2.arrowFunctionExpression(
23804
+ [t2.identifier(itemParamName), t2.identifier(indexParamName)],
23805
+ t2.identifier(indexParamName)
23806
+ );
23745
23807
  statements.push(
23746
23808
  t2.variableDeclaration("const", [
23747
23809
  t2.variableDeclarator(
23748
23810
  listId,
23749
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.list), [
23811
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.keyedList), [
23750
23812
  t2.arrowFunctionExpression([], arrayExpr),
23813
+ keyFn,
23751
23814
  callbackExpr,
23752
- t2.identifier(RUNTIME_ALIASES.createElement)
23815
+ t2.booleanLiteral(hasIndexParam)
23753
23816
  ])
23754
23817
  )
23755
23818
  ])
@@ -23869,8 +23932,8 @@ function buildPropsObject(attributes, ctx) {
23869
23932
  ]);
23870
23933
  })() : usesTracked && t2.isExpression(lowered) ? (() => {
23871
23934
  if (useMemoProp) {
23872
- ctx.helpersUsed.add("useProp");
23873
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
23935
+ ctx.helpersUsed.add("prop");
23936
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
23874
23937
  t2.arrowFunctionExpression(
23875
23938
  [],
23876
23939
  trackedExpr ?? lowered
@@ -24392,61 +24455,100 @@ function lowerFunctionWithRegions(fn, ctx) {
24392
24455
  const stmts = [];
24393
24456
  const excludeKeys = [];
24394
24457
  let supported = true;
24395
- let usesUseProp = false;
24458
+ let usesProp = false;
24396
24459
  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)) {
24460
+ let warnedNested = false;
24461
+ const memberExprForKey = (base, key) => t2.memberExpression(base, t2.identifier(key), false);
24462
+ const buildDestructure = (objectPattern, baseExpr, allowRest) => {
24463
+ for (const prop of objectPattern.properties) {
24464
+ if (t2.isObjectProperty(prop) && !prop.computed) {
24465
+ 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;
24466
+ if (!keyName) {
24467
+ reportDiagnostic(ctx, "FICT-P003" /* FICT_P003 */, prop);
24468
+ supported = false;
24469
+ warnedNested = true;
24470
+ break;
24471
+ }
24472
+ if (allowRest) {
24473
+ excludeKeys.push(t2.stringLiteral(keyName));
24474
+ }
24475
+ const member = memberExprForKey(baseExpr, keyName);
24476
+ const value = prop.value;
24477
+ if (t2.isIdentifier(value)) {
24478
+ const shouldWrapProp = !calledIdentifiers.has(value.name);
24479
+ if (shouldWrapProp) {
24480
+ usesProp = true;
24481
+ propsPlanAliases.add(value.name);
24482
+ }
24483
+ stmts.push(
24484
+ t2.variableDeclaration("const", [
24485
+ t2.variableDeclarator(
24486
+ t2.identifier(value.name),
24487
+ shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24488
+ t2.arrowFunctionExpression([], member)
24489
+ ]) : member
24490
+ )
24491
+ ])
24492
+ );
24493
+ continue;
24494
+ }
24495
+ if (t2.isObjectPattern(value)) {
24496
+ buildDestructure(value, member, false);
24497
+ if (!supported) break;
24498
+ continue;
24499
+ }
24500
+ if (t2.isAssignmentPattern(value) && t2.isIdentifier(value.left)) {
24501
+ const shouldWrapProp = !calledIdentifiers.has(value.left.name);
24502
+ if (shouldWrapProp) {
24503
+ usesProp = true;
24504
+ propsPlanAliases.add(value.left.name);
24505
+ }
24506
+ const baseInit = t2.logicalExpression("??", member, value.right);
24507
+ const init = shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24508
+ t2.arrowFunctionExpression([], baseInit)
24509
+ ]) : baseInit;
24510
+ stmts.push(
24511
+ t2.variableDeclaration("const", [
24512
+ t2.variableDeclarator(t2.identifier(value.left.name), init)
24513
+ ])
24514
+ );
24515
+ continue;
24516
+ }
24401
24517
  supported = false;
24518
+ if (!warnedNested) {
24519
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24520
+ warnedNested = true;
24521
+ }
24402
24522
  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);
24523
+ } else if (t2.isRestElement(prop) && allowRest && t2.isIdentifier(prop.argument)) {
24524
+ usesPropsRest = true;
24409
24525
  stmts.push(
24410
24526
  t2.variableDeclaration("const", [
24411
24527
  t2.variableDeclarator(
24412
- t2.identifier(prop.value.name),
24413
- t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24414
- t2.arrowFunctionExpression([], member)
24528
+ t2.identifier(prop.argument.name),
24529
+ t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), [
24530
+ baseExpr,
24531
+ t2.arrayExpression(excludeKeys)
24415
24532
  ])
24416
24533
  )
24417
24534
  ])
24418
24535
  );
24536
+ continue;
24419
24537
  } else {
24420
- stmts.push(
24421
- t2.variableDeclaration("const", [
24422
- t2.variableDeclarator(t2.identifier(prop.value.name), member)
24423
- ])
24424
- );
24538
+ supported = false;
24539
+ if (!warnedNested) {
24540
+ reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24541
+ warnedNested = true;
24542
+ }
24543
+ break;
24425
24544
  }
24426
- continue;
24427
- }
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
24545
  }
24443
- supported = false;
24444
- break;
24445
- }
24546
+ };
24547
+ buildDestructure(pattern, t2.identifier("__props"), true);
24446
24548
  if (supported) {
24447
24549
  propsDestructurePlan = {
24448
24550
  statements: stmts,
24449
- usesUseProp,
24551
+ usesProp,
24450
24552
  usesPropsRest
24451
24553
  };
24452
24554
  propsPlanAliases.forEach((name) => {
@@ -24540,8 +24642,8 @@ function lowerFunctionWithRegions(fn, ctx) {
24540
24642
  finalParams = [t2.identifier("__props")];
24541
24643
  const pattern = rawParam.type === "AssignmentPattern" ? rawParam.left : rawParam;
24542
24644
  if (propsDestructurePlan) {
24543
- if (propsDestructurePlan.usesUseProp) {
24544
- ctx.helpersUsed.add("useProp");
24645
+ if (propsDestructurePlan.usesProp) {
24646
+ ctx.helpersUsed.add("prop");
24545
24647
  }
24546
24648
  if (propsDestructurePlan.usesPropsRest) {
24547
24649
  ctx.helpersUsed.add("propsRest");
@@ -24610,6 +24712,38 @@ function flattenRegions(regions) {
24610
24712
  });
24611
24713
  }
24612
24714
 
24715
+ // src/utils.ts
24716
+ function isStateCall(node, t2) {
24717
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
24718
+ }
24719
+ function isEffectCall(node, t2) {
24720
+ return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
24721
+ }
24722
+ function getRootIdentifier(expr, t2) {
24723
+ if (t2.isIdentifier(expr)) {
24724
+ return expr;
24725
+ }
24726
+ if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
24727
+ return getRootIdentifier(expr.object, t2);
24728
+ }
24729
+ if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
24730
+ return getRootIdentifier(expr.object, t2);
24731
+ }
24732
+ if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
24733
+ return getRootIdentifier(expr.callee, t2);
24734
+ }
24735
+ if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
24736
+ return getRootIdentifier(expr.callee, t2);
24737
+ }
24738
+ if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
24739
+ return getRootIdentifier(expr.expression, t2);
24740
+ }
24741
+ if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
24742
+ return getRootIdentifier(expr.expression, t2);
24743
+ }
24744
+ return null;
24745
+ }
24746
+
24613
24747
  // src/index.ts
24614
24748
  function stripMacroImports(path, t2) {
24615
24749
  path.traverse({
@@ -24997,8 +25131,10 @@ function createHIREntrypointVisitor(t2, options) {
24997
25131
  const fileName = path.hub?.file?.opts?.filename || "<unknown>";
24998
25132
  const comments = path.hub?.file?.ast?.comments || [];
24999
25133
  const suppressions = parseSuppressions(comments);
25000
- const warn = createWarningDispatcher(options.onWarn, suppressions);
25001
- const optionsWithWarnings = { ...options, onWarn: warn };
25134
+ const dev = options.dev !== false;
25135
+ const warn = dev ? createWarningDispatcher(options.onWarn, suppressions) : () => {
25136
+ };
25137
+ const optionsWithWarnings = dev ? { ...options, onWarn: warn } : { ...options, onWarn: void 0 };
25002
25138
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
25003
25139
  const getFunctionName = (fnPath) => {
25004
25140
  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;
@@ -25254,6 +25390,18 @@ function createHIREntrypointVisitor(t2, options) {
25254
25390
  },
25255
25391
  CallExpression(callPath) {
25256
25392
  if (isStateCall(callPath.node, t2)) {
25393
+ const parentPath = callPath.parentPath;
25394
+ const isVariableDeclarator = parentPath?.isVariableDeclarator() && parentPath.node.init === callPath.node;
25395
+ if (!isVariableDeclarator) {
25396
+ throw callPath.buildCodeFrameError(
25397
+ "$state() must be assigned directly to a variable (e.g. let count = $state(0)). For object state, consider using $store from fict/plus."
25398
+ );
25399
+ }
25400
+ if (!t2.isIdentifier(parentPath.node.id)) {
25401
+ throw callPath.buildCodeFrameError(
25402
+ "Destructuring $state is not supported. Use a simple identifier."
25403
+ );
25404
+ }
25257
25405
  const ownerComponent = callPath.getFunctionParent();
25258
25406
  if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
25259
25407
  throw callPath.buildCodeFrameError(
@@ -25446,7 +25594,9 @@ function createHIREntrypointVisitor(t2, options) {
25446
25594
  }
25447
25595
  });
25448
25596
  }
25449
- runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25597
+ if (dev) {
25598
+ runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25599
+ }
25450
25600
  const fileAst = t2.file(path.node);
25451
25601
  const hir = buildHIR(fileAst);
25452
25602
  const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
@@ -25466,7 +25616,8 @@ var createFictPlugin = (0, import_helper_plugin_utils.declare)(
25466
25616
  const t2 = api.types;
25467
25617
  const normalizedOptions = {
25468
25618
  ...options,
25469
- fineGrainedDom: options.fineGrainedDom ?? true
25619
+ fineGrainedDom: options.fineGrainedDom ?? true,
25620
+ dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
25470
25621
  };
25471
25622
  return {
25472
25623
  name: "fict-compiler-hir",