@fictjs/compiler 0.0.13 → 0.0.15

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,7 +14165,7 @@ 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",
@@ -14173,7 +14199,7 @@ var RUNTIME_ALIASES = {
14173
14199
  fragment: "Fragment",
14174
14200
  propGetter: "__fictProp",
14175
14201
  propsRest: "__fictPropsRest",
14176
- useProp: "useProp",
14202
+ prop: "prop",
14177
14203
  mergeProps: "mergeProps",
14178
14204
  runInScope: "runInScope",
14179
14205
  createElement: "createElement",
@@ -14193,30 +14219,7 @@ var RUNTIME_ALIASES = {
14193
14219
  template: "template",
14194
14220
  delegateEvents: "delegateEvents"
14195
14221
  };
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
- ]);
14222
+ var DelegatedEvents = /* @__PURE__ */ new Set([...DelegatedEventNames]);
14220
14223
  var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
14221
14224
  // Console methods
14222
14225
  "console.log",
@@ -15556,6 +15559,17 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
15556
15559
  }
15557
15560
  function convertExpression(node) {
15558
15561
  const loc = getLoc(node);
15562
+ const convertCallArguments = (args) => args.map((arg) => {
15563
+ if (t.isSpreadElement(arg)) {
15564
+ return {
15565
+ kind: "SpreadElement",
15566
+ argument: convertExpression(arg.argument),
15567
+ loc: getLoc(arg)
15568
+ };
15569
+ }
15570
+ if (t.isExpression(arg)) return convertExpression(arg);
15571
+ return void 0;
15572
+ }).filter(Boolean);
15559
15573
  if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name, loc };
15560
15574
  if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node))
15561
15575
  return { kind: "Literal", value: node.value ?? null, loc };
@@ -15563,7 +15577,7 @@ function convertExpression(node) {
15563
15577
  const call = {
15564
15578
  kind: "CallExpression",
15565
15579
  callee: convertExpression(node.callee),
15566
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15580
+ arguments: convertCallArguments(node.arguments),
15567
15581
  loc
15568
15582
  };
15569
15583
  return call;
@@ -15843,7 +15857,7 @@ function convertExpression(node) {
15843
15857
  return {
15844
15858
  kind: "NewExpression",
15845
15859
  callee: convertExpression(node.callee),
15846
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15860
+ arguments: convertCallArguments(node.arguments),
15847
15861
  loc
15848
15862
  };
15849
15863
  }
@@ -15866,7 +15880,7 @@ function convertExpression(node) {
15866
15880
  return {
15867
15881
  kind: "OptionalCallExpression",
15868
15882
  callee: convertExpression(node.callee),
15869
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15883
+ arguments: convertCallArguments(node.arguments),
15870
15884
  optional: node.optional,
15871
15885
  loc
15872
15886
  };
@@ -16075,7 +16089,8 @@ var DiagnosticMessages = {
16075
16089
  ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
16076
16090
  ["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
16077
16091
  ["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.",
16092
+ ["FICT-P004" /* FICT_P004 */]: "Nested props destructuring falls back to non-reactive binding; access props directly or use prop.",
16093
+ ["FICT-P005" /* FICT_P005 */]: "Dynamic props spread may not stay reactive; consider explicit props or mergeProps(() => source).",
16079
16094
  ["FICT-S001" /* FICT_S001 */]: "State variable mutation detected outside component scope.",
16080
16095
  ["FICT-S002" /* FICT_S002 */]: "State variable escaped to external scope, may cause memory leaks.",
16081
16096
  ["FICT-E001" /* FICT_E001 */]: "Effect without reactive dependencies will run only once; consider adding state reads or removing the effect.",
@@ -16105,6 +16120,7 @@ var DiagnosticSeverities = {
16105
16120
  ["FICT-P002" /* FICT_P002 */]: "warning" /* Warning */,
16106
16121
  ["FICT-P003" /* FICT_P003 */]: "warning" /* Warning */,
16107
16122
  ["FICT-P004" /* FICT_P004 */]: "warning" /* Warning */,
16123
+ ["FICT-P005" /* FICT_P005 */]: "warning" /* Warning */,
16108
16124
  ["FICT-S001" /* FICT_S001 */]: "error" /* Error */,
16109
16125
  ["FICT-S002" /* FICT_S002 */]: "warning" /* Warning */,
16110
16126
  ["FICT-E001" /* FICT_E001 */]: "warning" /* Warning */,
@@ -16157,6 +16173,215 @@ function reportDiagnostic(ctx, code, node, context) {
16157
16173
  }
16158
16174
  }
16159
16175
 
16176
+ // src/ir/props-plan.ts
16177
+ function buildPropsPlan(attributes, children, ctx, helpers) {
16178
+ const { t: t2 } = ctx;
16179
+ const prevPropsContext = ctx.inPropsContext;
16180
+ ctx.inPropsContext = true;
16181
+ try {
16182
+ if (attributes.length === 0 && children.length === 0) return null;
16183
+ const segments = [];
16184
+ const flags = {
16185
+ needsMergeProps: false,
16186
+ hasLazySource: false
16187
+ };
16188
+ let bucket = [];
16189
+ const toPropKey = (name) => /^[a-zA-Z_$][\w$]*$/.test(name) ? t2.identifier(name) : t2.stringLiteral(name);
16190
+ const isAccessorName = (name) => (ctx.memoVars?.has(name) ?? false) || (ctx.signalVars?.has(name) ?? false) || (ctx.aliasVars?.has(name) ?? false);
16191
+ const isZeroArgFunction = (expr) => (t2.isArrowFunctionExpression(expr) || t2.isFunctionExpression(expr)) && expr.params.length === 0;
16192
+ const wrapAccessorSource = (node) => {
16193
+ if (t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.arguments.length === 0) {
16194
+ const baseName2 = helpers.deSSAVarName(node.callee.name);
16195
+ if (isAccessorName(baseName2)) {
16196
+ return t2.arrowFunctionExpression([], node);
16197
+ }
16198
+ }
16199
+ if (t2.isIdentifier(node)) {
16200
+ const baseName2 = helpers.deSSAVarName(node.name);
16201
+ if (isAccessorName(baseName2)) {
16202
+ return t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseName2), []));
16203
+ }
16204
+ }
16205
+ return node;
16206
+ };
16207
+ const isAccessorSource = (expr) => {
16208
+ if (expr.kind === "Identifier") {
16209
+ return isAccessorName(helpers.deSSAVarName(expr.name));
16210
+ }
16211
+ if (expr.kind === "CallExpression" || expr.kind === "OptionalCallExpression") {
16212
+ if (expr.callee.kind === "Identifier" && expr.arguments.length === 0) {
16213
+ return isAccessorName(helpers.deSSAVarName(expr.callee.name));
16214
+ }
16215
+ }
16216
+ return false;
16217
+ };
16218
+ const isRuntimeMergeProps = () => !ctx.shadowedNames?.has(RUNTIME_ALIASES.mergeProps) && !ctx.localDeclaredNames?.has(RUNTIME_ALIASES.mergeProps) && (!ctx.moduleDeclaredNames?.has(RUNTIME_ALIASES.mergeProps) || (ctx.moduleRuntimeNames?.has(RUNTIME_ALIASES.mergeProps) ?? false));
16219
+ const isMergePropsCall = (expr) => expr.kind === "CallExpression" && expr.callee.kind === "Identifier" && expr.callee.name === RUNTIME_ALIASES.mergeProps && isRuntimeMergeProps();
16220
+ const isDynamicMemberSpread = (expr) => {
16221
+ if (expr.kind !== "MemberExpression" && expr.kind !== "OptionalMemberExpression") return false;
16222
+ if (expr.computed) return true;
16223
+ if (expr.kind === "OptionalMemberExpression" && expr.optional) return true;
16224
+ let current = expr;
16225
+ while (current.kind === "MemberExpression" || current.kind === "OptionalMemberExpression") {
16226
+ const obj = current.object;
16227
+ if (obj.kind === "CallExpression" || obj.kind === "OptionalCallExpression" || obj.kind === "ConditionalExpression" || obj.kind === "LogicalExpression" || obj.kind === "SequenceExpression" || obj.kind === "AssignmentExpression" || obj.kind === "UpdateExpression" || obj.kind === "AwaitExpression" || obj.kind === "NewExpression" || obj.kind === "YieldExpression") {
16228
+ return true;
16229
+ }
16230
+ if (obj.kind === "OptionalMemberExpression" && obj.optional) {
16231
+ return true;
16232
+ }
16233
+ if (obj.kind !== "MemberExpression" && obj.kind !== "OptionalMemberExpression") {
16234
+ return obj.kind !== "Identifier";
16235
+ }
16236
+ current = obj;
16237
+ }
16238
+ return false;
16239
+ };
16240
+ const isDynamicPropsSpread = (expr) => {
16241
+ if (isAccessorSource(expr) || isMergePropsCall(expr)) return false;
16242
+ if (expr.kind === "CallExpression" || expr.kind === "OptionalCallExpression" || expr.kind === "ConditionalExpression" || expr.kind === "LogicalExpression" || expr.kind === "SequenceExpression" || expr.kind === "AssignmentExpression" || expr.kind === "UpdateExpression" || expr.kind === "AwaitExpression" || expr.kind === "NewExpression" || expr.kind === "YieldExpression") {
16243
+ return true;
16244
+ }
16245
+ if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
16246
+ return isDynamicMemberSpread(expr);
16247
+ }
16248
+ if (expr.kind === "ObjectExpression") {
16249
+ return expr.properties.some((p) => p.kind === "SpreadElement");
16250
+ }
16251
+ return false;
16252
+ };
16253
+ const flushBucket = () => {
16254
+ if (bucket.length === 0) return;
16255
+ segments.push({ kind: "object", properties: bucket });
16256
+ bucket = [];
16257
+ };
16258
+ const pushSpread = (expr) => {
16259
+ flags.needsMergeProps = true;
16260
+ if (isZeroArgFunction(expr)) {
16261
+ flags.hasLazySource = true;
16262
+ }
16263
+ segments.push({ kind: "spread", expr });
16264
+ };
16265
+ for (const attr of attributes) {
16266
+ if (attr.isSpread && attr.spreadExpr) {
16267
+ flushBucket();
16268
+ if (isDynamicPropsSpread(attr.spreadExpr)) {
16269
+ reportDiagnostic(ctx, "FICT-P005" /* FICT_P005 */, attr.spreadExpr);
16270
+ }
16271
+ let spreadExpr = helpers.lowerDomExpression(attr.spreadExpr, ctx);
16272
+ if (t2.isCallExpression(spreadExpr) && t2.isIdentifier(spreadExpr.callee) && spreadExpr.callee.name === RUNTIME_ALIASES.mergeProps && isRuntimeMergeProps()) {
16273
+ const callExpr = spreadExpr;
16274
+ const rewrittenArgs = callExpr.arguments.map(
16275
+ (arg) => t2.isExpression(arg) ? wrapAccessorSource(arg) : arg
16276
+ );
16277
+ if (rewrittenArgs.some((arg, idx) => arg !== callExpr.arguments[idx])) {
16278
+ spreadExpr = t2.callExpression(
16279
+ callExpr.callee,
16280
+ rewrittenArgs
16281
+ );
16282
+ }
16283
+ const flattenArgs = [];
16284
+ let canFlatten = true;
16285
+ for (const arg of rewrittenArgs) {
16286
+ if (t2.isExpression(arg)) {
16287
+ flattenArgs.push(arg);
16288
+ } else {
16289
+ canFlatten = false;
16290
+ break;
16291
+ }
16292
+ }
16293
+ if (canFlatten) {
16294
+ for (const arg of flattenArgs) {
16295
+ pushSpread(arg);
16296
+ }
16297
+ continue;
16298
+ }
16299
+ }
16300
+ spreadExpr = wrapAccessorSource(spreadExpr);
16301
+ pushSpread(spreadExpr);
16302
+ continue;
16303
+ }
16304
+ if (attr.value) {
16305
+ const isFunctionLike = attr.value.kind === "ArrowFunction" || attr.value.kind === "FunctionExpression";
16306
+ const prevPropsCtx = ctx.inPropsContext;
16307
+ if (isFunctionLike) {
16308
+ ctx.inPropsContext = false;
16309
+ }
16310
+ const lowered = helpers.lowerDomExpression(attr.value, ctx);
16311
+ if (isFunctionLike) {
16312
+ ctx.inPropsContext = prevPropsCtx;
16313
+ }
16314
+ const baseIdent = attr.value.kind === "Identifier" ? helpers.deSSAVarName(attr.value.name) : void 0;
16315
+ const isAccessorBase = baseIdent && ((ctx.memoVars?.has(baseIdent) ?? false) || (ctx.signalVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false));
16316
+ const isStoreBase = baseIdent ? ctx.storeVars?.has(baseIdent) ?? false : false;
16317
+ const alreadyGetter = isFunctionLike || (baseIdent ? isStoreBase || (ctx.memoVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false) : false);
16318
+ const usesTracked = (!ctx.nonReactiveScopeDepth || ctx.nonReactiveScopeDepth === 0) && helpers.expressionUsesTracked(attr.value, ctx) && !alreadyGetter;
16319
+ const trackedExpr = usesTracked ? helpers.lowerTrackedExpression(
16320
+ attr.value,
16321
+ ctx
16322
+ ) : null;
16323
+ const useMemoProp = usesTracked && trackedExpr && t2.isExpression(trackedExpr) && !t2.isIdentifier(trackedExpr) && !t2.isMemberExpression(trackedExpr) && !t2.isLiteral(trackedExpr);
16324
+ const valueExpr = !isFunctionLike && isAccessorBase && baseIdent ? (() => {
16325
+ ctx.helpersUsed.add("propGetter");
16326
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
16327
+ t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseIdent), []))
16328
+ ]);
16329
+ })() : usesTracked && t2.isExpression(lowered) ? (() => {
16330
+ if (useMemoProp) {
16331
+ ctx.helpersUsed.add("prop");
16332
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
16333
+ t2.arrowFunctionExpression([], trackedExpr ?? lowered)
16334
+ ]);
16335
+ }
16336
+ ctx.helpersUsed.add("propGetter");
16337
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
16338
+ t2.arrowFunctionExpression([], trackedExpr ?? lowered)
16339
+ ]);
16340
+ })() : lowered;
16341
+ bucket.push(t2.objectProperty(toPropKey(attr.name), valueExpr));
16342
+ continue;
16343
+ }
16344
+ bucket.push(t2.objectProperty(toPropKey(attr.name), t2.booleanLiteral(true)));
16345
+ }
16346
+ if (children.length === 1 && children[0]) {
16347
+ bucket.push(t2.objectProperty(t2.identifier("children"), children[0]));
16348
+ } else if (children.length > 1) {
16349
+ bucket.push(t2.objectProperty(t2.identifier("children"), t2.arrayExpression(children)));
16350
+ }
16351
+ flushBucket();
16352
+ if (segments.length === 0) return null;
16353
+ return { segments, flags };
16354
+ } finally {
16355
+ ctx.inPropsContext = prevPropsContext;
16356
+ }
16357
+ }
16358
+ function lowerPropsPlan(plan, ctx) {
16359
+ const { t: t2 } = ctx;
16360
+ const args = [];
16361
+ for (const segment of plan.segments) {
16362
+ if (segment.kind === "object") {
16363
+ if (segment.properties.length === 0) continue;
16364
+ args.push(t2.objectExpression(segment.properties));
16365
+ continue;
16366
+ }
16367
+ args.push(segment.expr);
16368
+ }
16369
+ if (args.length === 0) return null;
16370
+ if (!plan.flags.needsMergeProps) {
16371
+ return args[0] ?? null;
16372
+ }
16373
+ if (args.length === 1 && !plan.flags.hasLazySource) {
16374
+ return args[0];
16375
+ }
16376
+ ctx.helpersUsed.add("mergeProps");
16377
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.mergeProps), args);
16378
+ }
16379
+ function buildPropsExpression(attributes, children, ctx, helpers) {
16380
+ const plan = buildPropsPlan(attributes, children, ctx, helpers);
16381
+ if (!plan) return null;
16382
+ return lowerPropsPlan(plan, ctx);
16383
+ }
16384
+
16160
16385
  // src/ir/ssa.ts
16161
16386
  function analyzeCFG(blocks) {
16162
16387
  const predecessors = computePredecessors(blocks);
@@ -16654,6 +16879,9 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
16654
16879
  expr.arguments?.forEach((a) => collectExprReads(a, into, paths, bound));
16655
16880
  return;
16656
16881
  }
16882
+ case "SpreadElement":
16883
+ collectExprReads(expr.argument, into, paths, bound);
16884
+ return;
16657
16885
  case "MemberExpression":
16658
16886
  case "OptionalMemberExpression": {
16659
16887
  const depPath = extractDependencyPath(expr);
@@ -18148,11 +18376,15 @@ function containsJSXExpr(expr) {
18148
18376
  case "ArrayExpression":
18149
18377
  return expr.elements?.some((el) => containsJSXExpr(el)) ?? false;
18150
18378
  case "ObjectExpression":
18151
- return expr.properties?.some((p) => containsJSXExpr(p.value)) ?? false;
18379
+ return expr.properties?.some(
18380
+ (p) => p.kind === "SpreadElement" ? containsJSXExpr(p.argument) : containsJSXExpr(p.value)
18381
+ ) ?? false;
18152
18382
  case "ConditionalExpression":
18153
18383
  return containsJSXExpr(expr.consequent) || containsJSXExpr(expr.alternate);
18154
18384
  case "ArrowFunction":
18155
18385
  return containsJSXExpr(expr.body);
18386
+ case "SpreadElement":
18387
+ return containsJSXExpr(expr.argument);
18156
18388
  default:
18157
18389
  return false;
18158
18390
  }
@@ -18182,6 +18414,8 @@ function expressionUsesTracked(expr, ctx) {
18182
18414
  });
18183
18415
  case "TemplateLiteral":
18184
18416
  return expr.expressions.some((e) => expressionUsesTracked(e, ctx));
18417
+ case "SpreadElement":
18418
+ return expressionUsesTracked(expr.argument, ctx);
18185
18419
  default:
18186
18420
  return false;
18187
18421
  }
@@ -19470,8 +19704,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19470
19704
  const isStateCall2 = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && instr.value.callee.name === "$state";
19471
19705
  const inRegionMemo = ctx.inRegionMemo ?? false;
19472
19706
  const isFunctionValue = instr.value.kind === "ArrowFunction" || instr.value.kind === "FunctionExpression";
19473
- const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "useProp"].includes(instr.value.callee.name);
19474
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
19707
+ const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "prop"].includes(instr.value.callee.name);
19708
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
19475
19709
  const isMemoReturningCall = isAccessorReturningCall || isReactiveObjectCall;
19476
19710
  const lowerAssignedValue = (forceAssigned = false) => lowerExpressionWithDeSSA(instr.value, ctx, forceAssigned || isFunctionValue);
19477
19711
  const buildMemoCall = (expr) => {
@@ -20228,6 +20462,9 @@ function collectCalledIdentifiers(fn) {
20228
20462
  function createCodegenContext(t2) {
20229
20463
  return {
20230
20464
  t: t2,
20465
+ moduleDeclaredNames: /* @__PURE__ */ new Set(),
20466
+ moduleRuntimeNames: /* @__PURE__ */ new Set(),
20467
+ localDeclaredNames: /* @__PURE__ */ new Set(),
20231
20468
  helpersUsed: /* @__PURE__ */ new Set(),
20232
20469
  tempCounter: 0,
20233
20470
  trackedVars: /* @__PURE__ */ new Set(),
@@ -21105,7 +21342,7 @@ function computeReactiveAccessors(fn, ctx) {
21105
21342
  tracked.add(target);
21106
21343
  changed = true;
21107
21344
  }
21108
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
21345
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
21109
21346
  if (hasDataDep && !isSignal(target) && !isStore(target) && !isReactiveObjectCall) {
21110
21347
  memo.add(target);
21111
21348
  }
@@ -21372,8 +21609,7 @@ function lowerTerminator(block, ctx) {
21372
21609
  return applyLoc([]);
21373
21610
  }
21374
21611
  }
21375
- function attachHelperImports(ctx, body, t2) {
21376
- if (ctx.helpersUsed.size === 0) return body;
21612
+ function collectDeclaredNames(body, t2) {
21377
21613
  const declared = /* @__PURE__ */ new Set();
21378
21614
  const addPatternNames = (pattern) => {
21379
21615
  if (t2.isIdentifier(pattern)) {
@@ -21447,6 +21683,78 @@ function attachHelperImports(ctx, body, t2) {
21447
21683
  declared.add(stmt.declaration.name);
21448
21684
  }
21449
21685
  }
21686
+ return declared;
21687
+ }
21688
+ function collectRuntimeImportNames(body, t2) {
21689
+ const runtimeModules = /* @__PURE__ */ new Set([RUNTIME_MODULE, "@fictjs/runtime", "fict"]);
21690
+ const imported = /* @__PURE__ */ new Set();
21691
+ for (const stmt of body) {
21692
+ if (!t2.isImportDeclaration(stmt)) continue;
21693
+ if (!runtimeModules.has(stmt.source.value)) continue;
21694
+ for (const spec of stmt.specifiers) {
21695
+ imported.add(spec.local.name);
21696
+ }
21697
+ }
21698
+ return imported;
21699
+ }
21700
+ function collectLocalDeclaredNames(params, blocks, t2) {
21701
+ const declared = /* @__PURE__ */ new Set();
21702
+ const addPatternNames = (pattern) => {
21703
+ if (t2.isIdentifier(pattern)) {
21704
+ declared.add(deSSAVarName(pattern.name));
21705
+ return;
21706
+ }
21707
+ if (t2.isAssignmentPattern(pattern)) {
21708
+ addPatternNames(pattern.left);
21709
+ return;
21710
+ }
21711
+ if (t2.isRestElement(pattern)) {
21712
+ addPatternNames(pattern.argument);
21713
+ return;
21714
+ }
21715
+ if (t2.isObjectPattern(pattern)) {
21716
+ for (const prop of pattern.properties) {
21717
+ if (t2.isRestElement(prop)) {
21718
+ addPatternNames(prop.argument);
21719
+ } else if (t2.isObjectProperty(prop)) {
21720
+ addPatternNames(prop.value);
21721
+ }
21722
+ }
21723
+ return;
21724
+ }
21725
+ if (t2.isArrayPattern(pattern)) {
21726
+ for (const el of pattern.elements) {
21727
+ if (!el) continue;
21728
+ if (t2.isPatternLike(el)) addPatternNames(el);
21729
+ }
21730
+ }
21731
+ };
21732
+ params.forEach((param) => declared.add(deSSAVarName(param.name)));
21733
+ if (!blocks) return declared;
21734
+ for (const block of blocks) {
21735
+ for (const instr of block.instructions) {
21736
+ if (instr.kind !== "Assign") continue;
21737
+ const target = deSSAVarName(instr.target.name);
21738
+ const isFunctionDecl = instr.value.kind === "FunctionExpression" && !!instr.value.name && deSSAVarName(instr.value.name) === target;
21739
+ if (instr.declarationKind || isFunctionDecl) {
21740
+ declared.add(target);
21741
+ }
21742
+ }
21743
+ const term = block.terminator;
21744
+ if (term.kind === "ForOf" || term.kind === "ForIn") {
21745
+ declared.add(deSSAVarName(term.variable));
21746
+ if (term.pattern) {
21747
+ addPatternNames(term.pattern);
21748
+ }
21749
+ } else if (term.kind === "Try" && term.catchParam) {
21750
+ declared.add(deSSAVarName(term.catchParam));
21751
+ }
21752
+ }
21753
+ return declared;
21754
+ }
21755
+ function attachHelperImports(ctx, body, t2) {
21756
+ if (ctx.helpersUsed.size === 0) return body;
21757
+ const declared = collectDeclaredNames(body, t2);
21450
21758
  const specifiers = [];
21451
21759
  for (const name of ctx.helpersUsed) {
21452
21760
  const alias = RUNTIME_ALIASES[name];
@@ -21516,11 +21824,21 @@ function lowerExpression(expr, ctx, isAssigned = false) {
21516
21824
  function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21517
21825
  const { t: t2 } = ctx;
21518
21826
  const mapParams = (params) => params.map((p) => t2.identifier(deSSAVarName(p.name)));
21519
- const withFunctionScope = (paramNames, fn) => {
21827
+ const lowerArgsAsExpressions = (args) => args.map(
21828
+ (arg) => arg.kind === "SpreadElement" ? lowerExpression(arg.argument, ctx) : lowerExpression(arg, ctx)
21829
+ );
21830
+ const lowerCallArguments = (args, mapArg) => args.map((arg, idx) => {
21831
+ if (arg.kind === "SpreadElement") {
21832
+ return t2.spreadElement(lowerExpression(arg.argument, ctx));
21833
+ }
21834
+ return mapArg ? mapArg(arg, idx) : lowerExpression(arg, ctx);
21835
+ });
21836
+ const withFunctionScope = (paramNames, fn, localDeclared) => {
21520
21837
  const prevTracked = ctx.trackedVars;
21521
21838
  const prevAlias = ctx.aliasVars;
21522
21839
  const prevExternal = ctx.externalTracked;
21523
21840
  const prevShadowed = ctx.shadowedNames;
21841
+ const prevLocalDeclared = ctx.localDeclaredNames;
21524
21842
  const scoped = new Set(ctx.trackedVars);
21525
21843
  paramNames.forEach((n) => scoped.delete(deSSAVarName(n)));
21526
21844
  ctx.trackedVars = scoped;
@@ -21529,11 +21847,19 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21529
21847
  const shadowed = new Set(prevShadowed ?? []);
21530
21848
  paramNames.forEach((n) => shadowed.add(deSSAVarName(n)));
21531
21849
  ctx.shadowedNames = shadowed;
21850
+ const localNames = new Set(prevLocalDeclared ?? []);
21851
+ if (localDeclared) {
21852
+ for (const name of localDeclared) {
21853
+ localNames.add(deSSAVarName(name));
21854
+ }
21855
+ }
21856
+ ctx.localDeclaredNames = localNames;
21532
21857
  const result = fn();
21533
21858
  ctx.trackedVars = prevTracked;
21534
21859
  ctx.aliasVars = prevAlias;
21535
21860
  ctx.externalTracked = prevExternal;
21536
21861
  ctx.shadowedNames = prevShadowed;
21862
+ ctx.localDeclaredNames = prevLocalDeclared;
21537
21863
  return result;
21538
21864
  };
21539
21865
  const lowerBlocksToStatements = (blocks) => {
@@ -21595,7 +21921,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21595
21921
  ctx.needsCtx = true;
21596
21922
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useSignal), [
21597
21923
  t2.identifier("__fictCtx"),
21598
- ...expr.arguments.map((a) => lowerExpression(a, ctx))
21924
+ ...lowerCallArguments(expr.arguments)
21599
21925
  ]);
21600
21926
  }
21601
21927
  if (expr.callee.kind === "Identifier" && expr.callee.name === "$effect") {
@@ -21603,14 +21929,15 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21603
21929
  ctx.needsCtx = true;
21604
21930
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
21605
21931
  t2.identifier("__fictCtx"),
21606
- ...expr.arguments.map(
21932
+ ...lowerCallArguments(
21933
+ expr.arguments,
21607
21934
  (arg) => arg.kind === "ArrowFunction" || arg.kind === "FunctionExpression" ? withNonReactiveScope(ctx, () => lowerExpression(arg, ctx)) : lowerExpression(arg, ctx)
21608
21935
  )
21609
21936
  ]);
21610
21937
  }
21611
21938
  if (expr.callee.kind === "Identifier" && expr.callee.name === "__forOf") {
21612
21939
  ctx.needsForOfHelper = true;
21613
- const [iterable, cb] = expr.arguments.map((a) => lowerExpression(a, ctx));
21940
+ const [iterable, cb] = lowerArgsAsExpressions(expr.arguments);
21614
21941
  return t2.callExpression(t2.identifier("__fictForOf"), [
21615
21942
  iterable ?? t2.identifier("undefined"),
21616
21943
  cb ?? t2.arrowFunctionExpression([], t2.identifier("undefined"))
@@ -21618,7 +21945,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21618
21945
  }
21619
21946
  if (expr.callee.kind === "Identifier" && expr.callee.name === "__forIn") {
21620
21947
  ctx.needsForInHelper = true;
21621
- const [obj, cb] = expr.arguments.map((a) => lowerExpression(a, ctx));
21948
+ const [obj, cb] = lowerArgsAsExpressions(expr.arguments);
21622
21949
  return t2.callExpression(t2.identifier("__fictForIn"), [
21623
21950
  obj ?? t2.identifier("undefined"),
21624
21951
  cb ?? t2.arrowFunctionExpression([], t2.identifier("undefined"))
@@ -21626,12 +21953,12 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21626
21953
  }
21627
21954
  if (expr.callee.kind === "Identifier" && expr.callee.name === "__fictPropsRest") {
21628
21955
  ctx.helpersUsed.add("propsRest");
21629
- const args = expr.arguments.map((a) => lowerExpression(a, ctx));
21956
+ const args = lowerCallArguments(expr.arguments);
21630
21957
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), args);
21631
21958
  }
21632
21959
  if (expr.callee.kind === "Identifier" && expr.callee.name === "mergeProps") {
21633
21960
  ctx.helpersUsed.add("mergeProps");
21634
- const args = expr.arguments.map((a) => lowerExpression(a, ctx));
21961
+ const args = lowerCallArguments(expr.arguments);
21635
21962
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.mergeProps), args);
21636
21963
  }
21637
21964
  const isIIFE = (expr.callee.kind === "ArrowFunction" || expr.callee.kind === "FunctionExpression") && expr.arguments.length === 0 && expr.callee.params.length === 0;
@@ -21639,7 +21966,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21639
21966
  const calleeIsMemoAccessor = !!calleeName && ctx.memoVars?.has(calleeName);
21640
21967
  const calleeIsSignalLike = !!calleeName && (ctx.signalVars?.has(calleeName) || ctx.storeVars?.has(calleeName));
21641
21968
  if (calleeIsMemoAccessor && !calleeIsSignalLike && expr.arguments.length > 0) {
21642
- const loweredArgs2 = expr.arguments.map((a) => lowerExpression(a, ctx));
21969
+ const loweredArgs2 = lowerCallArguments(expr.arguments);
21643
21970
  return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs2);
21644
21971
  }
21645
21972
  const lowerCallee = () => isIIFE ? withNonReactiveScope(ctx, () => lowerExpression(expr.callee, ctx)) : lowerExpression(expr.callee, ctx);
@@ -21648,7 +21975,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21648
21975
  ) || expr.callee.property.kind === "Literal" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
21649
21976
  String(expr.callee.property.value)
21650
21977
  ));
21651
- const loweredArgs = expr.arguments.map((a, idx) => {
21978
+ const loweredArgs = lowerCallArguments(expr.arguments, (a, idx) => {
21652
21979
  if (idx === 0 && isIteratingMethod && (a.kind === "ArrowFunction" || a.kind === "FunctionExpression")) {
21653
21980
  return withNoMemoAndDynamicHooks(ctx, () => lowerExpression(a, ctx));
21654
21981
  }
@@ -21728,8 +22055,8 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21728
22055
  const shouldMemoProp = usesTracked && !t2.isIdentifier(valueExprRaw) && !t2.isMemberExpression(valueExprRaw) && !t2.isLiteral(valueExprRaw);
21729
22056
  const valueExpr = usesTracked && ctx.t.isExpression(valueExprRaw) ? (() => {
21730
22057
  if (shouldMemoProp) {
21731
- ctx.helpersUsed.add("useProp");
21732
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
22058
+ ctx.helpersUsed.add("prop");
22059
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
21733
22060
  t2.arrowFunctionExpression([], valueExprRaw)
21734
22061
  ]);
21735
22062
  }
@@ -21754,67 +22081,81 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21754
22081
  case "ArrowFunction": {
21755
22082
  const paramIds = mapParams(expr.params);
21756
22083
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
22084
+ const localDeclared = collectLocalDeclaredNames(
22085
+ expr.params,
22086
+ Array.isArray(expr.body) ? expr.body : null,
22087
+ t2
22088
+ );
21757
22089
  return withNonReactiveScope(
21758
22090
  ctx,
21759
- () => withFunctionScope(shadowed, () => {
21760
- let fn;
21761
- if (expr.isExpression && !Array.isArray(expr.body)) {
21762
- const { result: bodyExpr, cacheDeclarations } = withGetterCache(
21763
- ctx,
21764
- () => lowerTrackedExpression(expr.body, ctx)
21765
- );
21766
- if (cacheDeclarations.length > 0) {
22091
+ () => withFunctionScope(
22092
+ shadowed,
22093
+ () => {
22094
+ let fn;
22095
+ if (expr.isExpression && !Array.isArray(expr.body)) {
22096
+ const { result: bodyExpr, cacheDeclarations } = withGetterCache(
22097
+ ctx,
22098
+ () => lowerTrackedExpression(expr.body, ctx)
22099
+ );
22100
+ if (cacheDeclarations.length > 0) {
22101
+ fn = t2.arrowFunctionExpression(
22102
+ paramIds,
22103
+ t2.blockStatement([...cacheDeclarations, t2.returnStatement(bodyExpr)])
22104
+ );
22105
+ } else {
22106
+ fn = t2.arrowFunctionExpression(paramIds, bodyExpr);
22107
+ }
22108
+ } else if (Array.isArray(expr.body)) {
22109
+ const { result: stmts, cacheDeclarations } = withGetterCache(
22110
+ ctx,
22111
+ () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
22112
+ );
21767
22113
  fn = t2.arrowFunctionExpression(
21768
22114
  paramIds,
21769
- t2.blockStatement([...cacheDeclarations, t2.returnStatement(bodyExpr)])
22115
+ t2.blockStatement([...cacheDeclarations, ...stmts])
21770
22116
  );
21771
22117
  } else {
21772
- fn = t2.arrowFunctionExpression(paramIds, bodyExpr);
22118
+ fn = t2.arrowFunctionExpression(paramIds, t2.blockStatement([]));
21773
22119
  }
21774
- } else if (Array.isArray(expr.body)) {
21775
- const { result: stmts, cacheDeclarations } = withGetterCache(
21776
- ctx,
21777
- () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
21778
- );
21779
- fn = t2.arrowFunctionExpression(
21780
- paramIds,
21781
- t2.blockStatement([...cacheDeclarations, ...stmts])
21782
- );
21783
- } else {
21784
- fn = t2.arrowFunctionExpression(paramIds, t2.blockStatement([]));
21785
- }
21786
- fn.async = expr.isAsync ?? false;
21787
- return fn;
21788
- })
22120
+ fn.async = expr.isAsync ?? false;
22121
+ return fn;
22122
+ },
22123
+ localDeclared
22124
+ )
21789
22125
  );
21790
22126
  }
21791
22127
  case "FunctionExpression": {
21792
22128
  const paramIds = mapParams(expr.params);
21793
22129
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
22130
+ const localDeclared = collectLocalDeclaredNames(expr.params, expr.body, t2);
21794
22131
  return withNonReactiveScope(
21795
22132
  ctx,
21796
- () => withFunctionScope(shadowed, () => {
21797
- let fn;
21798
- if (Array.isArray(expr.body)) {
21799
- const { result: stmts, cacheDeclarations } = withGetterCache(
21800
- ctx,
21801
- () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
21802
- );
21803
- fn = t2.functionExpression(
21804
- expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
21805
- paramIds,
21806
- t2.blockStatement([...cacheDeclarations, ...stmts])
21807
- );
21808
- } else {
21809
- fn = t2.functionExpression(
21810
- expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
21811
- paramIds,
21812
- t2.blockStatement([])
21813
- );
21814
- }
21815
- fn.async = expr.isAsync ?? false;
21816
- return fn;
21817
- })
22133
+ () => withFunctionScope(
22134
+ shadowed,
22135
+ () => {
22136
+ let fn;
22137
+ if (Array.isArray(expr.body)) {
22138
+ const { result: stmts, cacheDeclarations } = withGetterCache(
22139
+ ctx,
22140
+ () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
22141
+ );
22142
+ fn = t2.functionExpression(
22143
+ expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
22144
+ paramIds,
22145
+ t2.blockStatement([...cacheDeclarations, ...stmts])
22146
+ );
22147
+ } else {
22148
+ fn = t2.functionExpression(
22149
+ expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
22150
+ paramIds,
22151
+ t2.blockStatement([])
22152
+ );
22153
+ }
22154
+ fn.async = expr.isAsync ?? false;
22155
+ return fn;
22156
+ },
22157
+ localDeclared
22158
+ )
21818
22159
  );
21819
22160
  }
21820
22161
  case "AssignmentExpression":
@@ -21948,10 +22289,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21948
22289
  case "AwaitExpression":
21949
22290
  return t2.awaitExpression(lowerExpression(expr.argument, ctx));
21950
22291
  case "NewExpression":
21951
- return t2.newExpression(
21952
- lowerExpression(expr.callee, ctx),
21953
- expr.arguments.map((a) => lowerExpression(a, ctx))
21954
- );
22292
+ return t2.newExpression(lowerExpression(expr.callee, ctx), lowerCallArguments(expr.arguments));
21955
22293
  case "SequenceExpression":
21956
22294
  return t2.sequenceExpression(expr.expressions.map((e) => lowerExpression(e, ctx)));
21957
22295
  case "YieldExpression":
@@ -21962,7 +22300,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21962
22300
  case "OptionalCallExpression":
21963
22301
  return t2.optionalCallExpression(
21964
22302
  lowerExpression(expr.callee, ctx),
21965
- expr.arguments.map((a) => lowerExpression(a, ctx)),
22303
+ lowerCallArguments(expr.arguments),
21966
22304
  expr.optional
21967
22305
  );
21968
22306
  case "TaggedTemplateExpression":
@@ -22094,26 +22432,17 @@ function lowerJSXElement(jsx, ctx) {
22094
22432
  ]);
22095
22433
  }
22096
22434
  ctx.helpersUsed.add("createElement");
22097
- const propsObj = buildPropsObject(jsx.attributes, ctx);
22098
22435
  const children = jsx.children.map((c) => lowerJSXChild(c, ctx));
22436
+ const propsExpr = buildPropsExpression(jsx.attributes, children, ctx, {
22437
+ lowerDomExpression,
22438
+ lowerTrackedExpression,
22439
+ expressionUsesTracked,
22440
+ deSSAVarName
22441
+ });
22099
22442
  const componentRef = typeof jsx.tagName === "string" ? t2.identifier(jsx.tagName) : lowerExpression(jsx.tagName, ctx);
22100
- const propsWithChildren = [];
22101
- if (propsObj && t2.isObjectExpression(propsObj)) {
22102
- propsWithChildren.push(...propsObj.properties);
22103
- }
22104
- if (children.length === 1 && children[0]) {
22105
- propsWithChildren.push(t2.objectProperty(t2.identifier("children"), children[0]));
22106
- } else if (children.length > 1) {
22107
- propsWithChildren.push(
22108
- t2.objectProperty(t2.identifier("children"), t2.arrayExpression(children))
22109
- );
22110
- }
22111
22443
  return t2.objectExpression([
22112
22444
  t2.objectProperty(t2.identifier("type"), componentRef),
22113
- t2.objectProperty(
22114
- t2.identifier("props"),
22115
- propsWithChildren.length > 0 ? t2.objectExpression(propsWithChildren) : t2.nullLiteral()
22116
- )
22445
+ t2.objectProperty(t2.identifier("props"), propsExpr ?? t2.nullLiteral())
22117
22446
  ]);
22118
22447
  }
22119
22448
  const useFineGrainedDom = !ctx.noMemo;
@@ -23866,98 +24195,6 @@ function lowerJSXChild(child, ctx) {
23866
24195
  return applyRegionMetadataToExpression(lowerExpression(child.value, ctx), ctx);
23867
24196
  }
23868
24197
  }
23869
- function buildPropsObject(attributes, ctx) {
23870
- const { t: t2 } = ctx;
23871
- const prevPropsContext = ctx.inPropsContext;
23872
- ctx.inPropsContext = true;
23873
- try {
23874
- if (attributes.length === 0) return null;
23875
- const properties = [];
23876
- const spreads = [];
23877
- const toPropKey = (name) => /^[a-zA-Z_$][\w$]*$/.test(name) ? t2.identifier(name) : t2.stringLiteral(name);
23878
- const isAccessorName = (name) => (ctx.memoVars?.has(name) ?? false) || (ctx.signalVars?.has(name) ?? false) || (ctx.aliasVars?.has(name) ?? false);
23879
- const wrapAccessorSource = (node) => {
23880
- if (t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.arguments.length === 0) {
23881
- const baseName2 = deSSAVarName(node.callee.name);
23882
- if (isAccessorName(baseName2)) {
23883
- return t2.arrowFunctionExpression([], node);
23884
- }
23885
- }
23886
- if (t2.isIdentifier(node)) {
23887
- const baseName2 = deSSAVarName(node.name);
23888
- if (isAccessorName(baseName2)) {
23889
- return t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseName2), []));
23890
- }
23891
- }
23892
- return node;
23893
- };
23894
- for (const attr of attributes) {
23895
- if (attr.isSpread && attr.spreadExpr) {
23896
- let spreadExpr = lowerDomExpression(attr.spreadExpr, ctx);
23897
- if (t2.isCallExpression(spreadExpr)) {
23898
- const callExpr = spreadExpr;
23899
- const rewrittenArgs = callExpr.arguments.map(
23900
- (arg) => t2.isExpression(arg) ? wrapAccessorSource(arg) : arg
23901
- );
23902
- if (rewrittenArgs.some((arg, idx) => arg !== callExpr.arguments[idx])) {
23903
- spreadExpr = t2.callExpression(callExpr.callee, rewrittenArgs);
23904
- }
23905
- }
23906
- spreadExpr = wrapAccessorSource(spreadExpr);
23907
- spreads.push(t2.spreadElement(spreadExpr));
23908
- } else if (attr.value) {
23909
- const isFunctionLike = attr.value.kind === "ArrowFunction" || attr.value.kind === "FunctionExpression";
23910
- const prevPropsCtx = ctx.inPropsContext;
23911
- if (isFunctionLike) {
23912
- ctx.inPropsContext = false;
23913
- }
23914
- const lowered = lowerDomExpression(attr.value, ctx);
23915
- if (isFunctionLike) {
23916
- ctx.inPropsContext = prevPropsCtx;
23917
- }
23918
- const baseIdent = attr.value.kind === "Identifier" ? deSSAVarName(attr.value.name) : void 0;
23919
- const isAccessorBase = baseIdent && ((ctx.memoVars?.has(baseIdent) ?? false) || (ctx.signalVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false));
23920
- const isStoreBase = baseIdent ? ctx.storeVars?.has(baseIdent) ?? false : false;
23921
- const alreadyGetter = isFunctionLike || (baseIdent ? isStoreBase || (ctx.memoVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false) : false);
23922
- const usesTracked = (!ctx.nonReactiveScopeDepth || ctx.nonReactiveScopeDepth === 0) && expressionUsesTracked(attr.value, ctx) && !alreadyGetter;
23923
- const trackedExpr = usesTracked ? lowerTrackedExpression(attr.value, ctx) : null;
23924
- const useMemoProp = usesTracked && trackedExpr && t2.isExpression(trackedExpr) && !t2.isIdentifier(trackedExpr) && !t2.isMemberExpression(trackedExpr) && !t2.isLiteral(trackedExpr);
23925
- const valueExpr = !isFunctionLike && isAccessorBase && baseIdent ? (() => {
23926
- ctx.helpersUsed.add("propGetter");
23927
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
23928
- t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseIdent), []))
23929
- ]);
23930
- })() : usesTracked && t2.isExpression(lowered) ? (() => {
23931
- if (useMemoProp) {
23932
- ctx.helpersUsed.add("useProp");
23933
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
23934
- t2.arrowFunctionExpression(
23935
- [],
23936
- trackedExpr ?? lowered
23937
- )
23938
- ]);
23939
- }
23940
- ctx.helpersUsed.add("propGetter");
23941
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
23942
- t2.arrowFunctionExpression(
23943
- [],
23944
- trackedExpr ?? lowered
23945
- )
23946
- ]);
23947
- })() : lowered;
23948
- properties.push(t2.objectProperty(toPropKey(attr.name), valueExpr));
23949
- } else {
23950
- properties.push(t2.objectProperty(toPropKey(attr.name), t2.booleanLiteral(true)));
23951
- }
23952
- }
23953
- if (spreads.length > 0) {
23954
- return t2.objectExpression([...spreads, ...properties]);
23955
- }
23956
- return t2.objectExpression(properties);
23957
- } finally {
23958
- ctx.inPropsContext = prevPropsContext;
23959
- }
23960
- }
23961
24198
  function isDOMProperty(name) {
23962
24199
  return ["value", "checked", "selected", "disabled", "readOnly", "multiple", "muted"].includes(
23963
24200
  name
@@ -23974,6 +24211,8 @@ function lowerHIRWithRegions(program, t2, options) {
23974
24211
  let topLevelCtxInjected = false;
23975
24212
  const emittedFunctionNames = /* @__PURE__ */ new Set();
23976
24213
  const originalBody = program.originalBody ?? [];
24214
+ ctx.moduleDeclaredNames = collectDeclaredNames(originalBody, t2);
24215
+ ctx.moduleRuntimeNames = collectRuntimeImportNames(originalBody, t2);
23977
24216
  for (const stmt of originalBody) {
23978
24217
  if (t2.isVariableDeclaration(stmt)) {
23979
24218
  for (const decl of stmt.declarations) {
@@ -24371,6 +24610,12 @@ function lowerFunctionWithRegions(fn, ctx) {
24371
24610
  const functionShadowed = new Set(prevShadowed ?? []);
24372
24611
  shadowedParams.forEach((n) => functionShadowed.add(n));
24373
24612
  ctx.shadowedNames = functionShadowed;
24613
+ const prevLocalDeclared = ctx.localDeclaredNames;
24614
+ const localDeclared = new Set(prevLocalDeclared ?? []);
24615
+ for (const name of collectLocalDeclaredNames(fn.params, fn.blocks, t2)) {
24616
+ localDeclared.add(name);
24617
+ }
24618
+ ctx.localDeclaredNames = localDeclared;
24374
24619
  const prevExternalTracked = ctx.externalTracked;
24375
24620
  const inheritedTracked = new Set(ctx.trackedVars);
24376
24621
  ctx.externalTracked = inheritedTracked;
@@ -24452,16 +24697,75 @@ function lowerFunctionWithRegions(fn, ctx) {
24452
24697
  const stmts = [];
24453
24698
  const excludeKeys = [];
24454
24699
  let supported = true;
24455
- let usesUseProp = false;
24700
+ let usesProp = false;
24456
24701
  let usesPropsRest = false;
24457
24702
  let warnedNested = false;
24703
+ const reportedPatternNodes = /* @__PURE__ */ new Set();
24704
+ const reportPatternDiagnostic = (node, code) => {
24705
+ if (reportedPatternNodes.has(node)) return;
24706
+ reportedPatternNodes.add(node);
24707
+ reportDiagnostic(ctx, code, node);
24708
+ };
24709
+ const reportPropsPatternIssues = (objectPattern, allowRest) => {
24710
+ for (const prop of objectPattern.properties) {
24711
+ if (t2.isObjectProperty(prop)) {
24712
+ if (prop.computed) {
24713
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24714
+ continue;
24715
+ }
24716
+ 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;
24717
+ if (!keyName) {
24718
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24719
+ continue;
24720
+ }
24721
+ const value = prop.value;
24722
+ if (t2.isIdentifier(value)) {
24723
+ continue;
24724
+ }
24725
+ if (t2.isObjectPattern(value)) {
24726
+ reportPropsPatternIssues(value, false);
24727
+ continue;
24728
+ }
24729
+ if (t2.isAssignmentPattern(value)) {
24730
+ if (t2.isIdentifier(value.left)) {
24731
+ continue;
24732
+ }
24733
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24734
+ continue;
24735
+ }
24736
+ if (t2.isArrayPattern(value)) {
24737
+ const hasRest = value.elements.some((el) => t2.isRestElement(el));
24738
+ reportPatternDiagnostic(
24739
+ value,
24740
+ hasRest ? "FICT-P002" /* FICT_P002 */ : "FICT-P001" /* FICT_P001 */
24741
+ );
24742
+ continue;
24743
+ }
24744
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24745
+ continue;
24746
+ }
24747
+ if (t2.isRestElement(prop)) {
24748
+ if (!allowRest || !t2.isIdentifier(prop.argument)) {
24749
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24750
+ }
24751
+ continue;
24752
+ }
24753
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24754
+ }
24755
+ };
24458
24756
  const memberExprForKey = (base, key) => t2.memberExpression(base, t2.identifier(key), false);
24459
24757
  const buildDestructure = (objectPattern, baseExpr, allowRest) => {
24460
24758
  for (const prop of objectPattern.properties) {
24461
- if (t2.isObjectProperty(prop) && !prop.computed) {
24759
+ if (t2.isObjectProperty(prop)) {
24760
+ if (prop.computed) {
24761
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24762
+ supported = false;
24763
+ warnedNested = true;
24764
+ break;
24765
+ }
24462
24766
  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
24767
  if (!keyName) {
24464
- reportDiagnostic(ctx, "FICT-P003" /* FICT_P003 */, prop);
24768
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24465
24769
  supported = false;
24466
24770
  warnedNested = true;
24467
24771
  break;
@@ -24472,16 +24776,16 @@ function lowerFunctionWithRegions(fn, ctx) {
24472
24776
  const member = memberExprForKey(baseExpr, keyName);
24473
24777
  const value = prop.value;
24474
24778
  if (t2.isIdentifier(value)) {
24475
- const shouldUseProp = !calledIdentifiers.has(value.name);
24476
- if (shouldUseProp) {
24477
- usesUseProp = true;
24779
+ const shouldWrapProp = !calledIdentifiers.has(value.name);
24780
+ if (shouldWrapProp) {
24781
+ usesProp = true;
24478
24782
  propsPlanAliases.add(value.name);
24479
24783
  }
24480
24784
  stmts.push(
24481
24785
  t2.variableDeclaration("const", [
24482
24786
  t2.variableDeclarator(
24483
24787
  t2.identifier(value.name),
24484
- shouldUseProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24788
+ shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24485
24789
  t2.arrowFunctionExpression([], member)
24486
24790
  ]) : member
24487
24791
  )
@@ -24494,26 +24798,44 @@ function lowerFunctionWithRegions(fn, ctx) {
24494
24798
  if (!supported) break;
24495
24799
  continue;
24496
24800
  }
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);
24801
+ if (t2.isAssignmentPattern(value)) {
24802
+ if (t2.isIdentifier(value.left)) {
24803
+ const shouldWrapProp = !calledIdentifiers.has(value.left.name);
24804
+ if (shouldWrapProp) {
24805
+ usesProp = true;
24806
+ propsPlanAliases.add(value.left.name);
24807
+ }
24808
+ const baseInit = t2.logicalExpression("??", member, value.right);
24809
+ const init = shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24810
+ t2.arrowFunctionExpression([], baseInit)
24811
+ ]) : baseInit;
24812
+ stmts.push(
24813
+ t2.variableDeclaration("const", [
24814
+ t2.variableDeclarator(t2.identifier(value.left.name), init)
24815
+ ])
24816
+ );
24817
+ continue;
24502
24818
  }
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
- ])
24819
+ supported = false;
24820
+ if (!warnedNested) {
24821
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24822
+ warnedNested = true;
24823
+ }
24824
+ break;
24825
+ }
24826
+ if (t2.isArrayPattern(value)) {
24827
+ const hasRest = value.elements.some((el) => t2.isRestElement(el));
24828
+ reportPatternDiagnostic(
24829
+ value,
24830
+ hasRest ? "FICT-P002" /* FICT_P002 */ : "FICT-P001" /* FICT_P001 */
24511
24831
  );
24512
- continue;
24832
+ supported = false;
24833
+ warnedNested = true;
24834
+ break;
24513
24835
  }
24514
24836
  supported = false;
24515
24837
  if (!warnedNested) {
24516
- reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24838
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24517
24839
  warnedNested = true;
24518
24840
  }
24519
24841
  break;
@@ -24534,18 +24856,19 @@ function lowerFunctionWithRegions(fn, ctx) {
24534
24856
  } else {
24535
24857
  supported = false;
24536
24858
  if (!warnedNested) {
24537
- reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24859
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24538
24860
  warnedNested = true;
24539
24861
  }
24540
24862
  break;
24541
24863
  }
24542
24864
  }
24543
24865
  };
24866
+ reportPropsPatternIssues(pattern, true);
24544
24867
  buildDestructure(pattern, t2.identifier("__props"), true);
24545
24868
  if (supported) {
24546
24869
  propsDestructurePlan = {
24547
24870
  statements: stmts,
24548
- usesUseProp,
24871
+ usesProp,
24549
24872
  usesPropsRest
24550
24873
  };
24551
24874
  propsPlanAliases.forEach((name) => {
@@ -24587,6 +24910,7 @@ function lowerFunctionWithRegions(fn, ctx) {
24587
24910
  if (!hasJSX && !hasTrackedValues) {
24588
24911
  ctx.needsCtx = prevNeedsCtx;
24589
24912
  ctx.shadowedNames = prevShadowed;
24913
+ ctx.localDeclaredNames = prevLocalDeclared;
24590
24914
  ctx.trackedVars = prevTracked;
24591
24915
  ctx.externalTracked = prevExternalTracked;
24592
24916
  ctx.signalVars = prevSignalVars;
@@ -24639,8 +24963,8 @@ function lowerFunctionWithRegions(fn, ctx) {
24639
24963
  finalParams = [t2.identifier("__props")];
24640
24964
  const pattern = rawParam.type === "AssignmentPattern" ? rawParam.left : rawParam;
24641
24965
  if (propsDestructurePlan) {
24642
- if (propsDestructurePlan.usesUseProp) {
24643
- ctx.helpersUsed.add("useProp");
24966
+ if (propsDestructurePlan.usesProp) {
24967
+ ctx.helpersUsed.add("prop");
24644
24968
  }
24645
24969
  if (propsDestructurePlan.usesPropsRest) {
24646
24970
  ctx.helpersUsed.add("propsRest");
@@ -24669,6 +24993,7 @@ function lowerFunctionWithRegions(fn, ctx) {
24669
24993
  );
24670
24994
  ctx.needsCtx = prevNeedsCtx;
24671
24995
  ctx.shadowedNames = prevShadowed;
24996
+ ctx.localDeclaredNames = prevLocalDeclared;
24672
24997
  ctx.trackedVars = prevTracked;
24673
24998
  ctx.externalTracked = prevExternalTracked;
24674
24999
  ctx.signalVars = prevSignalVars;
@@ -25128,8 +25453,10 @@ function createHIREntrypointVisitor(t2, options) {
25128
25453
  const fileName = path.hub?.file?.opts?.filename || "<unknown>";
25129
25454
  const comments = path.hub?.file?.ast?.comments || [];
25130
25455
  const suppressions = parseSuppressions(comments);
25131
- const warn = createWarningDispatcher(options.onWarn, suppressions);
25132
- const optionsWithWarnings = { ...options, onWarn: warn };
25456
+ const dev = options.dev !== false;
25457
+ const warn = dev ? createWarningDispatcher(options.onWarn, suppressions) : () => {
25458
+ };
25459
+ const optionsWithWarnings = dev ? { ...options, onWarn: warn } : { ...options, onWarn: void 0 };
25133
25460
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
25134
25461
  const getFunctionName = (fnPath) => {
25135
25462
  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;
@@ -25385,6 +25712,18 @@ function createHIREntrypointVisitor(t2, options) {
25385
25712
  },
25386
25713
  CallExpression(callPath) {
25387
25714
  if (isStateCall(callPath.node, t2)) {
25715
+ const parentPath = callPath.parentPath;
25716
+ const isVariableDeclarator = parentPath?.isVariableDeclarator() && parentPath.node.init === callPath.node;
25717
+ if (!isVariableDeclarator) {
25718
+ throw callPath.buildCodeFrameError(
25719
+ "$state() must be assigned directly to a variable (e.g. let count = $state(0)). For object state, consider using $store from fict/plus."
25720
+ );
25721
+ }
25722
+ if (!t2.isIdentifier(parentPath.node.id)) {
25723
+ throw callPath.buildCodeFrameError(
25724
+ "Destructuring $state is not supported. Use a simple identifier."
25725
+ );
25726
+ }
25388
25727
  const ownerComponent = callPath.getFunctionParent();
25389
25728
  if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
25390
25729
  throw callPath.buildCodeFrameError(
@@ -25577,7 +25916,9 @@ function createHIREntrypointVisitor(t2, options) {
25577
25916
  }
25578
25917
  });
25579
25918
  }
25580
- runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25919
+ if (dev) {
25920
+ runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25921
+ }
25581
25922
  const fileAst = t2.file(path.node);
25582
25923
  const hir = buildHIR(fileAst);
25583
25924
  const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
@@ -25597,7 +25938,8 @@ var createFictPlugin = (0, import_helper_plugin_utils.declare)(
25597
25938
  const t2 = api.types;
25598
25939
  const normalizedOptions = {
25599
25940
  ...options,
25600
- fineGrainedDom: options.fineGrainedDom ?? true
25941
+ fineGrainedDom: options.fineGrainedDom ?? true,
25942
+ dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
25601
25943
  };
25602
25944
  return {
25603
25945
  name: "fict-compiler-hir",