@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.js CHANGED
@@ -14109,8 +14109,34 @@ var require_lib3 = __commonJS({
14109
14109
  // src/index.ts
14110
14110
  import { declare } from "@babel/helper-plugin-utils";
14111
14111
 
14112
+ // ../runtime/src/delegated-events.ts
14113
+ var DelegatedEventNames = [
14114
+ "beforeinput",
14115
+ "click",
14116
+ "dblclick",
14117
+ "contextmenu",
14118
+ "focusin",
14119
+ "focusout",
14120
+ "input",
14121
+ "keydown",
14122
+ "keyup",
14123
+ "mousedown",
14124
+ "mousemove",
14125
+ "mouseout",
14126
+ "mouseover",
14127
+ "mouseup",
14128
+ "pointerdown",
14129
+ "pointermove",
14130
+ "pointerout",
14131
+ "pointerover",
14132
+ "pointerup",
14133
+ "touchend",
14134
+ "touchmove",
14135
+ "touchstart"
14136
+ ];
14137
+
14112
14138
  // src/constants.ts
14113
- var RUNTIME_MODULE = "@fictjs/runtime";
14139
+ var RUNTIME_MODULE = "@fictjs/runtime/internal";
14114
14140
  var RUNTIME_HELPERS = {
14115
14141
  signal: "createSignal",
14116
14142
  createSelector: "createSelector",
@@ -14127,7 +14153,7 @@ var RUNTIME_HELPERS = {
14127
14153
  propGetter: "__fictProp",
14128
14154
  propsRest: "__fictPropsRest",
14129
14155
  mergeProps: "mergeProps",
14130
- useProp: "useProp",
14156
+ prop: "prop",
14131
14157
  runInScope: "runInScope",
14132
14158
  createElement: "createElement",
14133
14159
  conditional: "createConditional",
@@ -14161,7 +14187,7 @@ var RUNTIME_ALIASES = {
14161
14187
  fragment: "Fragment",
14162
14188
  propGetter: "__fictProp",
14163
14189
  propsRest: "__fictPropsRest",
14164
- useProp: "useProp",
14190
+ prop: "prop",
14165
14191
  mergeProps: "mergeProps",
14166
14192
  runInScope: "runInScope",
14167
14193
  createElement: "createElement",
@@ -14181,30 +14207,7 @@ var RUNTIME_ALIASES = {
14181
14207
  template: "template",
14182
14208
  delegateEvents: "delegateEvents"
14183
14209
  };
14184
- var DelegatedEvents = /* @__PURE__ */ new Set([
14185
- "beforeinput",
14186
- "click",
14187
- "dblclick",
14188
- "contextmenu",
14189
- "focusin",
14190
- "focusout",
14191
- "input",
14192
- "keydown",
14193
- "keyup",
14194
- "mousedown",
14195
- "mousemove",
14196
- "mouseout",
14197
- "mouseover",
14198
- "mouseup",
14199
- "pointerdown",
14200
- "pointermove",
14201
- "pointerout",
14202
- "pointerover",
14203
- "pointerup",
14204
- "touchend",
14205
- "touchmove",
14206
- "touchstart"
14207
- ]);
14210
+ var DelegatedEvents = /* @__PURE__ */ new Set([...DelegatedEventNames]);
14208
14211
  var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
14209
14212
  // Console methods
14210
14213
  "console.log",
@@ -15544,6 +15547,17 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
15544
15547
  }
15545
15548
  function convertExpression(node) {
15546
15549
  const loc = getLoc(node);
15550
+ const convertCallArguments = (args) => args.map((arg) => {
15551
+ if (t.isSpreadElement(arg)) {
15552
+ return {
15553
+ kind: "SpreadElement",
15554
+ argument: convertExpression(arg.argument),
15555
+ loc: getLoc(arg)
15556
+ };
15557
+ }
15558
+ if (t.isExpression(arg)) return convertExpression(arg);
15559
+ return void 0;
15560
+ }).filter(Boolean);
15547
15561
  if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name, loc };
15548
15562
  if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node))
15549
15563
  return { kind: "Literal", value: node.value ?? null, loc };
@@ -15551,7 +15565,7 @@ function convertExpression(node) {
15551
15565
  const call = {
15552
15566
  kind: "CallExpression",
15553
15567
  callee: convertExpression(node.callee),
15554
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15568
+ arguments: convertCallArguments(node.arguments),
15555
15569
  loc
15556
15570
  };
15557
15571
  return call;
@@ -15831,7 +15845,7 @@ function convertExpression(node) {
15831
15845
  return {
15832
15846
  kind: "NewExpression",
15833
15847
  callee: convertExpression(node.callee),
15834
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15848
+ arguments: convertCallArguments(node.arguments),
15835
15849
  loc
15836
15850
  };
15837
15851
  }
@@ -15854,7 +15868,7 @@ function convertExpression(node) {
15854
15868
  return {
15855
15869
  kind: "OptionalCallExpression",
15856
15870
  callee: convertExpression(node.callee),
15857
- arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
15871
+ arguments: convertCallArguments(node.arguments),
15858
15872
  optional: node.optional,
15859
15873
  loc
15860
15874
  };
@@ -16063,7 +16077,8 @@ var DiagnosticMessages = {
16063
16077
  ["FICT-P001" /* FICT_P001 */]: "Props destructuring falls back to non-reactive binding.",
16064
16078
  ["FICT-P002" /* FICT_P002 */]: "Array rest in props destructuring falls back to non-reactive binding.",
16065
16079
  ["FICT-P003" /* FICT_P003 */]: "Computed property in props pattern cannot be made reactive.",
16066
- ["FICT-P004" /* FICT_P004 */]: "Nested props destructuring falls back to non-reactive binding; access props directly or use useProp.",
16080
+ ["FICT-P004" /* FICT_P004 */]: "Nested props destructuring falls back to non-reactive binding; access props directly or use prop.",
16081
+ ["FICT-P005" /* FICT_P005 */]: "Dynamic props spread may not stay reactive; consider explicit props or mergeProps(() => source).",
16067
16082
  ["FICT-S001" /* FICT_S001 */]: "State variable mutation detected outside component scope.",
16068
16083
  ["FICT-S002" /* FICT_S002 */]: "State variable escaped to external scope, may cause memory leaks.",
16069
16084
  ["FICT-E001" /* FICT_E001 */]: "Effect without reactive dependencies will run only once; consider adding state reads or removing the effect.",
@@ -16093,6 +16108,7 @@ var DiagnosticSeverities = {
16093
16108
  ["FICT-P002" /* FICT_P002 */]: "warning" /* Warning */,
16094
16109
  ["FICT-P003" /* FICT_P003 */]: "warning" /* Warning */,
16095
16110
  ["FICT-P004" /* FICT_P004 */]: "warning" /* Warning */,
16111
+ ["FICT-P005" /* FICT_P005 */]: "warning" /* Warning */,
16096
16112
  ["FICT-S001" /* FICT_S001 */]: "error" /* Error */,
16097
16113
  ["FICT-S002" /* FICT_S002 */]: "warning" /* Warning */,
16098
16114
  ["FICT-E001" /* FICT_E001 */]: "warning" /* Warning */,
@@ -16145,6 +16161,215 @@ function reportDiagnostic(ctx, code, node, context) {
16145
16161
  }
16146
16162
  }
16147
16163
 
16164
+ // src/ir/props-plan.ts
16165
+ function buildPropsPlan(attributes, children, ctx, helpers) {
16166
+ const { t: t2 } = ctx;
16167
+ const prevPropsContext = ctx.inPropsContext;
16168
+ ctx.inPropsContext = true;
16169
+ try {
16170
+ if (attributes.length === 0 && children.length === 0) return null;
16171
+ const segments = [];
16172
+ const flags = {
16173
+ needsMergeProps: false,
16174
+ hasLazySource: false
16175
+ };
16176
+ let bucket = [];
16177
+ const toPropKey = (name) => /^[a-zA-Z_$][\w$]*$/.test(name) ? t2.identifier(name) : t2.stringLiteral(name);
16178
+ const isAccessorName = (name) => (ctx.memoVars?.has(name) ?? false) || (ctx.signalVars?.has(name) ?? false) || (ctx.aliasVars?.has(name) ?? false);
16179
+ const isZeroArgFunction = (expr) => (t2.isArrowFunctionExpression(expr) || t2.isFunctionExpression(expr)) && expr.params.length === 0;
16180
+ const wrapAccessorSource = (node) => {
16181
+ if (t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.arguments.length === 0) {
16182
+ const baseName2 = helpers.deSSAVarName(node.callee.name);
16183
+ if (isAccessorName(baseName2)) {
16184
+ return t2.arrowFunctionExpression([], node);
16185
+ }
16186
+ }
16187
+ if (t2.isIdentifier(node)) {
16188
+ const baseName2 = helpers.deSSAVarName(node.name);
16189
+ if (isAccessorName(baseName2)) {
16190
+ return t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseName2), []));
16191
+ }
16192
+ }
16193
+ return node;
16194
+ };
16195
+ const isAccessorSource = (expr) => {
16196
+ if (expr.kind === "Identifier") {
16197
+ return isAccessorName(helpers.deSSAVarName(expr.name));
16198
+ }
16199
+ if (expr.kind === "CallExpression" || expr.kind === "OptionalCallExpression") {
16200
+ if (expr.callee.kind === "Identifier" && expr.arguments.length === 0) {
16201
+ return isAccessorName(helpers.deSSAVarName(expr.callee.name));
16202
+ }
16203
+ }
16204
+ return false;
16205
+ };
16206
+ 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));
16207
+ const isMergePropsCall = (expr) => expr.kind === "CallExpression" && expr.callee.kind === "Identifier" && expr.callee.name === RUNTIME_ALIASES.mergeProps && isRuntimeMergeProps();
16208
+ const isDynamicMemberSpread = (expr) => {
16209
+ if (expr.kind !== "MemberExpression" && expr.kind !== "OptionalMemberExpression") return false;
16210
+ if (expr.computed) return true;
16211
+ if (expr.kind === "OptionalMemberExpression" && expr.optional) return true;
16212
+ let current = expr;
16213
+ while (current.kind === "MemberExpression" || current.kind === "OptionalMemberExpression") {
16214
+ const obj = current.object;
16215
+ 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") {
16216
+ return true;
16217
+ }
16218
+ if (obj.kind === "OptionalMemberExpression" && obj.optional) {
16219
+ return true;
16220
+ }
16221
+ if (obj.kind !== "MemberExpression" && obj.kind !== "OptionalMemberExpression") {
16222
+ return obj.kind !== "Identifier";
16223
+ }
16224
+ current = obj;
16225
+ }
16226
+ return false;
16227
+ };
16228
+ const isDynamicPropsSpread = (expr) => {
16229
+ if (isAccessorSource(expr) || isMergePropsCall(expr)) return false;
16230
+ 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") {
16231
+ return true;
16232
+ }
16233
+ if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
16234
+ return isDynamicMemberSpread(expr);
16235
+ }
16236
+ if (expr.kind === "ObjectExpression") {
16237
+ return expr.properties.some((p) => p.kind === "SpreadElement");
16238
+ }
16239
+ return false;
16240
+ };
16241
+ const flushBucket = () => {
16242
+ if (bucket.length === 0) return;
16243
+ segments.push({ kind: "object", properties: bucket });
16244
+ bucket = [];
16245
+ };
16246
+ const pushSpread = (expr) => {
16247
+ flags.needsMergeProps = true;
16248
+ if (isZeroArgFunction(expr)) {
16249
+ flags.hasLazySource = true;
16250
+ }
16251
+ segments.push({ kind: "spread", expr });
16252
+ };
16253
+ for (const attr of attributes) {
16254
+ if (attr.isSpread && attr.spreadExpr) {
16255
+ flushBucket();
16256
+ if (isDynamicPropsSpread(attr.spreadExpr)) {
16257
+ reportDiagnostic(ctx, "FICT-P005" /* FICT_P005 */, attr.spreadExpr);
16258
+ }
16259
+ let spreadExpr = helpers.lowerDomExpression(attr.spreadExpr, ctx);
16260
+ if (t2.isCallExpression(spreadExpr) && t2.isIdentifier(spreadExpr.callee) && spreadExpr.callee.name === RUNTIME_ALIASES.mergeProps && isRuntimeMergeProps()) {
16261
+ const callExpr = spreadExpr;
16262
+ const rewrittenArgs = callExpr.arguments.map(
16263
+ (arg) => t2.isExpression(arg) ? wrapAccessorSource(arg) : arg
16264
+ );
16265
+ if (rewrittenArgs.some((arg, idx) => arg !== callExpr.arguments[idx])) {
16266
+ spreadExpr = t2.callExpression(
16267
+ callExpr.callee,
16268
+ rewrittenArgs
16269
+ );
16270
+ }
16271
+ const flattenArgs = [];
16272
+ let canFlatten = true;
16273
+ for (const arg of rewrittenArgs) {
16274
+ if (t2.isExpression(arg)) {
16275
+ flattenArgs.push(arg);
16276
+ } else {
16277
+ canFlatten = false;
16278
+ break;
16279
+ }
16280
+ }
16281
+ if (canFlatten) {
16282
+ for (const arg of flattenArgs) {
16283
+ pushSpread(arg);
16284
+ }
16285
+ continue;
16286
+ }
16287
+ }
16288
+ spreadExpr = wrapAccessorSource(spreadExpr);
16289
+ pushSpread(spreadExpr);
16290
+ continue;
16291
+ }
16292
+ if (attr.value) {
16293
+ const isFunctionLike = attr.value.kind === "ArrowFunction" || attr.value.kind === "FunctionExpression";
16294
+ const prevPropsCtx = ctx.inPropsContext;
16295
+ if (isFunctionLike) {
16296
+ ctx.inPropsContext = false;
16297
+ }
16298
+ const lowered = helpers.lowerDomExpression(attr.value, ctx);
16299
+ if (isFunctionLike) {
16300
+ ctx.inPropsContext = prevPropsCtx;
16301
+ }
16302
+ const baseIdent = attr.value.kind === "Identifier" ? helpers.deSSAVarName(attr.value.name) : void 0;
16303
+ const isAccessorBase = baseIdent && ((ctx.memoVars?.has(baseIdent) ?? false) || (ctx.signalVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false));
16304
+ const isStoreBase = baseIdent ? ctx.storeVars?.has(baseIdent) ?? false : false;
16305
+ const alreadyGetter = isFunctionLike || (baseIdent ? isStoreBase || (ctx.memoVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false) : false);
16306
+ const usesTracked = (!ctx.nonReactiveScopeDepth || ctx.nonReactiveScopeDepth === 0) && helpers.expressionUsesTracked(attr.value, ctx) && !alreadyGetter;
16307
+ const trackedExpr = usesTracked ? helpers.lowerTrackedExpression(
16308
+ attr.value,
16309
+ ctx
16310
+ ) : null;
16311
+ const useMemoProp = usesTracked && trackedExpr && t2.isExpression(trackedExpr) && !t2.isIdentifier(trackedExpr) && !t2.isMemberExpression(trackedExpr) && !t2.isLiteral(trackedExpr);
16312
+ const valueExpr = !isFunctionLike && isAccessorBase && baseIdent ? (() => {
16313
+ ctx.helpersUsed.add("propGetter");
16314
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
16315
+ t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseIdent), []))
16316
+ ]);
16317
+ })() : usesTracked && t2.isExpression(lowered) ? (() => {
16318
+ if (useMemoProp) {
16319
+ ctx.helpersUsed.add("prop");
16320
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
16321
+ t2.arrowFunctionExpression([], trackedExpr ?? lowered)
16322
+ ]);
16323
+ }
16324
+ ctx.helpersUsed.add("propGetter");
16325
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
16326
+ t2.arrowFunctionExpression([], trackedExpr ?? lowered)
16327
+ ]);
16328
+ })() : lowered;
16329
+ bucket.push(t2.objectProperty(toPropKey(attr.name), valueExpr));
16330
+ continue;
16331
+ }
16332
+ bucket.push(t2.objectProperty(toPropKey(attr.name), t2.booleanLiteral(true)));
16333
+ }
16334
+ if (children.length === 1 && children[0]) {
16335
+ bucket.push(t2.objectProperty(t2.identifier("children"), children[0]));
16336
+ } else if (children.length > 1) {
16337
+ bucket.push(t2.objectProperty(t2.identifier("children"), t2.arrayExpression(children)));
16338
+ }
16339
+ flushBucket();
16340
+ if (segments.length === 0) return null;
16341
+ return { segments, flags };
16342
+ } finally {
16343
+ ctx.inPropsContext = prevPropsContext;
16344
+ }
16345
+ }
16346
+ function lowerPropsPlan(plan, ctx) {
16347
+ const { t: t2 } = ctx;
16348
+ const args = [];
16349
+ for (const segment of plan.segments) {
16350
+ if (segment.kind === "object") {
16351
+ if (segment.properties.length === 0) continue;
16352
+ args.push(t2.objectExpression(segment.properties));
16353
+ continue;
16354
+ }
16355
+ args.push(segment.expr);
16356
+ }
16357
+ if (args.length === 0) return null;
16358
+ if (!plan.flags.needsMergeProps) {
16359
+ return args[0] ?? null;
16360
+ }
16361
+ if (args.length === 1 && !plan.flags.hasLazySource) {
16362
+ return args[0];
16363
+ }
16364
+ ctx.helpersUsed.add("mergeProps");
16365
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.mergeProps), args);
16366
+ }
16367
+ function buildPropsExpression(attributes, children, ctx, helpers) {
16368
+ const plan = buildPropsPlan(attributes, children, ctx, helpers);
16369
+ if (!plan) return null;
16370
+ return lowerPropsPlan(plan, ctx);
16371
+ }
16372
+
16148
16373
  // src/ir/ssa.ts
16149
16374
  function analyzeCFG(blocks) {
16150
16375
  const predecessors = computePredecessors(blocks);
@@ -16642,6 +16867,9 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
16642
16867
  expr.arguments?.forEach((a) => collectExprReads(a, into, paths, bound));
16643
16868
  return;
16644
16869
  }
16870
+ case "SpreadElement":
16871
+ collectExprReads(expr.argument, into, paths, bound);
16872
+ return;
16645
16873
  case "MemberExpression":
16646
16874
  case "OptionalMemberExpression": {
16647
16875
  const depPath = extractDependencyPath(expr);
@@ -18136,11 +18364,15 @@ function containsJSXExpr(expr) {
18136
18364
  case "ArrayExpression":
18137
18365
  return expr.elements?.some((el) => containsJSXExpr(el)) ?? false;
18138
18366
  case "ObjectExpression":
18139
- return expr.properties?.some((p) => containsJSXExpr(p.value)) ?? false;
18367
+ return expr.properties?.some(
18368
+ (p) => p.kind === "SpreadElement" ? containsJSXExpr(p.argument) : containsJSXExpr(p.value)
18369
+ ) ?? false;
18140
18370
  case "ConditionalExpression":
18141
18371
  return containsJSXExpr(expr.consequent) || containsJSXExpr(expr.alternate);
18142
18372
  case "ArrowFunction":
18143
18373
  return containsJSXExpr(expr.body);
18374
+ case "SpreadElement":
18375
+ return containsJSXExpr(expr.argument);
18144
18376
  default:
18145
18377
  return false;
18146
18378
  }
@@ -18170,6 +18402,8 @@ function expressionUsesTracked(expr, ctx) {
18170
18402
  });
18171
18403
  case "TemplateLiteral":
18172
18404
  return expr.expressions.some((e) => expressionUsesTracked(e, ctx));
18405
+ case "SpreadElement":
18406
+ return expressionUsesTracked(expr.argument, ctx);
18173
18407
  default:
18174
18408
  return false;
18175
18409
  }
@@ -19458,8 +19692,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
19458
19692
  const isStateCall2 = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && instr.value.callee.name === "$state";
19459
19693
  const inRegionMemo = ctx.inRegionMemo ?? false;
19460
19694
  const isFunctionValue = instr.value.kind === "ArrowFunction" || instr.value.kind === "FunctionExpression";
19461
- const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "useProp"].includes(instr.value.callee.name);
19462
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
19695
+ const isAccessorReturningCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["$memo", "createMemo", "prop"].includes(instr.value.callee.name);
19696
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
19463
19697
  const isMemoReturningCall = isAccessorReturningCall || isReactiveObjectCall;
19464
19698
  const lowerAssignedValue = (forceAssigned = false) => lowerExpressionWithDeSSA(instr.value, ctx, forceAssigned || isFunctionValue);
19465
19699
  const buildMemoCall = (expr) => {
@@ -20216,6 +20450,9 @@ function collectCalledIdentifiers(fn) {
20216
20450
  function createCodegenContext(t2) {
20217
20451
  return {
20218
20452
  t: t2,
20453
+ moduleDeclaredNames: /* @__PURE__ */ new Set(),
20454
+ moduleRuntimeNames: /* @__PURE__ */ new Set(),
20455
+ localDeclaredNames: /* @__PURE__ */ new Set(),
20219
20456
  helpersUsed: /* @__PURE__ */ new Set(),
20220
20457
  tempCounter: 0,
20221
20458
  trackedVars: /* @__PURE__ */ new Set(),
@@ -21093,7 +21330,7 @@ function computeReactiveAccessors(fn, ctx) {
21093
21330
  tracked.add(target);
21094
21331
  changed = true;
21095
21332
  }
21096
- const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps", "prop"].includes(instr.value.callee.name);
21333
+ const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
21097
21334
  if (hasDataDep && !isSignal(target) && !isStore(target) && !isReactiveObjectCall) {
21098
21335
  memo.add(target);
21099
21336
  }
@@ -21360,8 +21597,7 @@ function lowerTerminator(block, ctx) {
21360
21597
  return applyLoc([]);
21361
21598
  }
21362
21599
  }
21363
- function attachHelperImports(ctx, body, t2) {
21364
- if (ctx.helpersUsed.size === 0) return body;
21600
+ function collectDeclaredNames(body, t2) {
21365
21601
  const declared = /* @__PURE__ */ new Set();
21366
21602
  const addPatternNames = (pattern) => {
21367
21603
  if (t2.isIdentifier(pattern)) {
@@ -21435,6 +21671,78 @@ function attachHelperImports(ctx, body, t2) {
21435
21671
  declared.add(stmt.declaration.name);
21436
21672
  }
21437
21673
  }
21674
+ return declared;
21675
+ }
21676
+ function collectRuntimeImportNames(body, t2) {
21677
+ const runtimeModules = /* @__PURE__ */ new Set([RUNTIME_MODULE, "@fictjs/runtime", "fict"]);
21678
+ const imported = /* @__PURE__ */ new Set();
21679
+ for (const stmt of body) {
21680
+ if (!t2.isImportDeclaration(stmt)) continue;
21681
+ if (!runtimeModules.has(stmt.source.value)) continue;
21682
+ for (const spec of stmt.specifiers) {
21683
+ imported.add(spec.local.name);
21684
+ }
21685
+ }
21686
+ return imported;
21687
+ }
21688
+ function collectLocalDeclaredNames(params, blocks, t2) {
21689
+ const declared = /* @__PURE__ */ new Set();
21690
+ const addPatternNames = (pattern) => {
21691
+ if (t2.isIdentifier(pattern)) {
21692
+ declared.add(deSSAVarName(pattern.name));
21693
+ return;
21694
+ }
21695
+ if (t2.isAssignmentPattern(pattern)) {
21696
+ addPatternNames(pattern.left);
21697
+ return;
21698
+ }
21699
+ if (t2.isRestElement(pattern)) {
21700
+ addPatternNames(pattern.argument);
21701
+ return;
21702
+ }
21703
+ if (t2.isObjectPattern(pattern)) {
21704
+ for (const prop of pattern.properties) {
21705
+ if (t2.isRestElement(prop)) {
21706
+ addPatternNames(prop.argument);
21707
+ } else if (t2.isObjectProperty(prop)) {
21708
+ addPatternNames(prop.value);
21709
+ }
21710
+ }
21711
+ return;
21712
+ }
21713
+ if (t2.isArrayPattern(pattern)) {
21714
+ for (const el of pattern.elements) {
21715
+ if (!el) continue;
21716
+ if (t2.isPatternLike(el)) addPatternNames(el);
21717
+ }
21718
+ }
21719
+ };
21720
+ params.forEach((param) => declared.add(deSSAVarName(param.name)));
21721
+ if (!blocks) return declared;
21722
+ for (const block of blocks) {
21723
+ for (const instr of block.instructions) {
21724
+ if (instr.kind !== "Assign") continue;
21725
+ const target = deSSAVarName(instr.target.name);
21726
+ const isFunctionDecl = instr.value.kind === "FunctionExpression" && !!instr.value.name && deSSAVarName(instr.value.name) === target;
21727
+ if (instr.declarationKind || isFunctionDecl) {
21728
+ declared.add(target);
21729
+ }
21730
+ }
21731
+ const term = block.terminator;
21732
+ if (term.kind === "ForOf" || term.kind === "ForIn") {
21733
+ declared.add(deSSAVarName(term.variable));
21734
+ if (term.pattern) {
21735
+ addPatternNames(term.pattern);
21736
+ }
21737
+ } else if (term.kind === "Try" && term.catchParam) {
21738
+ declared.add(deSSAVarName(term.catchParam));
21739
+ }
21740
+ }
21741
+ return declared;
21742
+ }
21743
+ function attachHelperImports(ctx, body, t2) {
21744
+ if (ctx.helpersUsed.size === 0) return body;
21745
+ const declared = collectDeclaredNames(body, t2);
21438
21746
  const specifiers = [];
21439
21747
  for (const name of ctx.helpersUsed) {
21440
21748
  const alias = RUNTIME_ALIASES[name];
@@ -21504,11 +21812,21 @@ function lowerExpression(expr, ctx, isAssigned = false) {
21504
21812
  function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21505
21813
  const { t: t2 } = ctx;
21506
21814
  const mapParams = (params) => params.map((p) => t2.identifier(deSSAVarName(p.name)));
21507
- const withFunctionScope = (paramNames, fn) => {
21815
+ const lowerArgsAsExpressions = (args) => args.map(
21816
+ (arg) => arg.kind === "SpreadElement" ? lowerExpression(arg.argument, ctx) : lowerExpression(arg, ctx)
21817
+ );
21818
+ const lowerCallArguments = (args, mapArg) => args.map((arg, idx) => {
21819
+ if (arg.kind === "SpreadElement") {
21820
+ return t2.spreadElement(lowerExpression(arg.argument, ctx));
21821
+ }
21822
+ return mapArg ? mapArg(arg, idx) : lowerExpression(arg, ctx);
21823
+ });
21824
+ const withFunctionScope = (paramNames, fn, localDeclared) => {
21508
21825
  const prevTracked = ctx.trackedVars;
21509
21826
  const prevAlias = ctx.aliasVars;
21510
21827
  const prevExternal = ctx.externalTracked;
21511
21828
  const prevShadowed = ctx.shadowedNames;
21829
+ const prevLocalDeclared = ctx.localDeclaredNames;
21512
21830
  const scoped = new Set(ctx.trackedVars);
21513
21831
  paramNames.forEach((n) => scoped.delete(deSSAVarName(n)));
21514
21832
  ctx.trackedVars = scoped;
@@ -21517,11 +21835,19 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21517
21835
  const shadowed = new Set(prevShadowed ?? []);
21518
21836
  paramNames.forEach((n) => shadowed.add(deSSAVarName(n)));
21519
21837
  ctx.shadowedNames = shadowed;
21838
+ const localNames = new Set(prevLocalDeclared ?? []);
21839
+ if (localDeclared) {
21840
+ for (const name of localDeclared) {
21841
+ localNames.add(deSSAVarName(name));
21842
+ }
21843
+ }
21844
+ ctx.localDeclaredNames = localNames;
21520
21845
  const result = fn();
21521
21846
  ctx.trackedVars = prevTracked;
21522
21847
  ctx.aliasVars = prevAlias;
21523
21848
  ctx.externalTracked = prevExternal;
21524
21849
  ctx.shadowedNames = prevShadowed;
21850
+ ctx.localDeclaredNames = prevLocalDeclared;
21525
21851
  return result;
21526
21852
  };
21527
21853
  const lowerBlocksToStatements = (blocks) => {
@@ -21583,7 +21909,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21583
21909
  ctx.needsCtx = true;
21584
21910
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useSignal), [
21585
21911
  t2.identifier("__fictCtx"),
21586
- ...expr.arguments.map((a) => lowerExpression(a, ctx))
21912
+ ...lowerCallArguments(expr.arguments)
21587
21913
  ]);
21588
21914
  }
21589
21915
  if (expr.callee.kind === "Identifier" && expr.callee.name === "$effect") {
@@ -21591,14 +21917,15 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21591
21917
  ctx.needsCtx = true;
21592
21918
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
21593
21919
  t2.identifier("__fictCtx"),
21594
- ...expr.arguments.map(
21920
+ ...lowerCallArguments(
21921
+ expr.arguments,
21595
21922
  (arg) => arg.kind === "ArrowFunction" || arg.kind === "FunctionExpression" ? withNonReactiveScope(ctx, () => lowerExpression(arg, ctx)) : lowerExpression(arg, ctx)
21596
21923
  )
21597
21924
  ]);
21598
21925
  }
21599
21926
  if (expr.callee.kind === "Identifier" && expr.callee.name === "__forOf") {
21600
21927
  ctx.needsForOfHelper = true;
21601
- const [iterable, cb] = expr.arguments.map((a) => lowerExpression(a, ctx));
21928
+ const [iterable, cb] = lowerArgsAsExpressions(expr.arguments);
21602
21929
  return t2.callExpression(t2.identifier("__fictForOf"), [
21603
21930
  iterable ?? t2.identifier("undefined"),
21604
21931
  cb ?? t2.arrowFunctionExpression([], t2.identifier("undefined"))
@@ -21606,7 +21933,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21606
21933
  }
21607
21934
  if (expr.callee.kind === "Identifier" && expr.callee.name === "__forIn") {
21608
21935
  ctx.needsForInHelper = true;
21609
- const [obj, cb] = expr.arguments.map((a) => lowerExpression(a, ctx));
21936
+ const [obj, cb] = lowerArgsAsExpressions(expr.arguments);
21610
21937
  return t2.callExpression(t2.identifier("__fictForIn"), [
21611
21938
  obj ?? t2.identifier("undefined"),
21612
21939
  cb ?? t2.arrowFunctionExpression([], t2.identifier("undefined"))
@@ -21614,12 +21941,12 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21614
21941
  }
21615
21942
  if (expr.callee.kind === "Identifier" && expr.callee.name === "__fictPropsRest") {
21616
21943
  ctx.helpersUsed.add("propsRest");
21617
- const args = expr.arguments.map((a) => lowerExpression(a, ctx));
21944
+ const args = lowerCallArguments(expr.arguments);
21618
21945
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propsRest), args);
21619
21946
  }
21620
21947
  if (expr.callee.kind === "Identifier" && expr.callee.name === "mergeProps") {
21621
21948
  ctx.helpersUsed.add("mergeProps");
21622
- const args = expr.arguments.map((a) => lowerExpression(a, ctx));
21949
+ const args = lowerCallArguments(expr.arguments);
21623
21950
  return t2.callExpression(t2.identifier(RUNTIME_ALIASES.mergeProps), args);
21624
21951
  }
21625
21952
  const isIIFE = (expr.callee.kind === "ArrowFunction" || expr.callee.kind === "FunctionExpression") && expr.arguments.length === 0 && expr.callee.params.length === 0;
@@ -21627,7 +21954,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21627
21954
  const calleeIsMemoAccessor = !!calleeName && ctx.memoVars?.has(calleeName);
21628
21955
  const calleeIsSignalLike = !!calleeName && (ctx.signalVars?.has(calleeName) || ctx.storeVars?.has(calleeName));
21629
21956
  if (calleeIsMemoAccessor && !calleeIsSignalLike && expr.arguments.length > 0) {
21630
- const loweredArgs2 = expr.arguments.map((a) => lowerExpression(a, ctx));
21957
+ const loweredArgs2 = lowerCallArguments(expr.arguments);
21631
21958
  return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs2);
21632
21959
  }
21633
21960
  const lowerCallee = () => isIIFE ? withNonReactiveScope(ctx, () => lowerExpression(expr.callee, ctx)) : lowerExpression(expr.callee, ctx);
@@ -21636,7 +21963,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21636
21963
  ) || expr.callee.property.kind === "Literal" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
21637
21964
  String(expr.callee.property.value)
21638
21965
  ));
21639
- const loweredArgs = expr.arguments.map((a, idx) => {
21966
+ const loweredArgs = lowerCallArguments(expr.arguments, (a, idx) => {
21640
21967
  if (idx === 0 && isIteratingMethod && (a.kind === "ArrowFunction" || a.kind === "FunctionExpression")) {
21641
21968
  return withNoMemoAndDynamicHooks(ctx, () => lowerExpression(a, ctx));
21642
21969
  }
@@ -21716,8 +22043,8 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21716
22043
  const shouldMemoProp = usesTracked && !t2.isIdentifier(valueExprRaw) && !t2.isMemberExpression(valueExprRaw) && !t2.isLiteral(valueExprRaw);
21717
22044
  const valueExpr = usesTracked && ctx.t.isExpression(valueExprRaw) ? (() => {
21718
22045
  if (shouldMemoProp) {
21719
- ctx.helpersUsed.add("useProp");
21720
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
22046
+ ctx.helpersUsed.add("prop");
22047
+ return t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
21721
22048
  t2.arrowFunctionExpression([], valueExprRaw)
21722
22049
  ]);
21723
22050
  }
@@ -21742,67 +22069,81 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21742
22069
  case "ArrowFunction": {
21743
22070
  const paramIds = mapParams(expr.params);
21744
22071
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
22072
+ const localDeclared = collectLocalDeclaredNames(
22073
+ expr.params,
22074
+ Array.isArray(expr.body) ? expr.body : null,
22075
+ t2
22076
+ );
21745
22077
  return withNonReactiveScope(
21746
22078
  ctx,
21747
- () => withFunctionScope(shadowed, () => {
21748
- let fn;
21749
- if (expr.isExpression && !Array.isArray(expr.body)) {
21750
- const { result: bodyExpr, cacheDeclarations } = withGetterCache(
21751
- ctx,
21752
- () => lowerTrackedExpression(expr.body, ctx)
21753
- );
21754
- if (cacheDeclarations.length > 0) {
22079
+ () => withFunctionScope(
22080
+ shadowed,
22081
+ () => {
22082
+ let fn;
22083
+ if (expr.isExpression && !Array.isArray(expr.body)) {
22084
+ const { result: bodyExpr, cacheDeclarations } = withGetterCache(
22085
+ ctx,
22086
+ () => lowerTrackedExpression(expr.body, ctx)
22087
+ );
22088
+ if (cacheDeclarations.length > 0) {
22089
+ fn = t2.arrowFunctionExpression(
22090
+ paramIds,
22091
+ t2.blockStatement([...cacheDeclarations, t2.returnStatement(bodyExpr)])
22092
+ );
22093
+ } else {
22094
+ fn = t2.arrowFunctionExpression(paramIds, bodyExpr);
22095
+ }
22096
+ } else if (Array.isArray(expr.body)) {
22097
+ const { result: stmts, cacheDeclarations } = withGetterCache(
22098
+ ctx,
22099
+ () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
22100
+ );
21755
22101
  fn = t2.arrowFunctionExpression(
21756
22102
  paramIds,
21757
- t2.blockStatement([...cacheDeclarations, t2.returnStatement(bodyExpr)])
22103
+ t2.blockStatement([...cacheDeclarations, ...stmts])
21758
22104
  );
21759
22105
  } else {
21760
- fn = t2.arrowFunctionExpression(paramIds, bodyExpr);
22106
+ fn = t2.arrowFunctionExpression(paramIds, t2.blockStatement([]));
21761
22107
  }
21762
- } else if (Array.isArray(expr.body)) {
21763
- const { result: stmts, cacheDeclarations } = withGetterCache(
21764
- ctx,
21765
- () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
21766
- );
21767
- fn = t2.arrowFunctionExpression(
21768
- paramIds,
21769
- t2.blockStatement([...cacheDeclarations, ...stmts])
21770
- );
21771
- } else {
21772
- fn = t2.arrowFunctionExpression(paramIds, t2.blockStatement([]));
21773
- }
21774
- fn.async = expr.isAsync ?? false;
21775
- return fn;
21776
- })
22108
+ fn.async = expr.isAsync ?? false;
22109
+ return fn;
22110
+ },
22111
+ localDeclared
22112
+ )
21777
22113
  );
21778
22114
  }
21779
22115
  case "FunctionExpression": {
21780
22116
  const paramIds = mapParams(expr.params);
21781
22117
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
22118
+ const localDeclared = collectLocalDeclaredNames(expr.params, expr.body, t2);
21782
22119
  return withNonReactiveScope(
21783
22120
  ctx,
21784
- () => withFunctionScope(shadowed, () => {
21785
- let fn;
21786
- if (Array.isArray(expr.body)) {
21787
- const { result: stmts, cacheDeclarations } = withGetterCache(
21788
- ctx,
21789
- () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
21790
- );
21791
- fn = t2.functionExpression(
21792
- expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
21793
- paramIds,
21794
- t2.blockStatement([...cacheDeclarations, ...stmts])
21795
- );
21796
- } else {
21797
- fn = t2.functionExpression(
21798
- expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
21799
- paramIds,
21800
- t2.blockStatement([])
21801
- );
21802
- }
21803
- fn.async = expr.isAsync ?? false;
21804
- return fn;
21805
- })
22121
+ () => withFunctionScope(
22122
+ shadowed,
22123
+ () => {
22124
+ let fn;
22125
+ if (Array.isArray(expr.body)) {
22126
+ const { result: stmts, cacheDeclarations } = withGetterCache(
22127
+ ctx,
22128
+ () => lowerStructuredBlocks(expr.body, expr.params, paramIds)
22129
+ );
22130
+ fn = t2.functionExpression(
22131
+ expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
22132
+ paramIds,
22133
+ t2.blockStatement([...cacheDeclarations, ...stmts])
22134
+ );
22135
+ } else {
22136
+ fn = t2.functionExpression(
22137
+ expr.name ? t2.identifier(deSSAVarName(expr.name)) : null,
22138
+ paramIds,
22139
+ t2.blockStatement([])
22140
+ );
22141
+ }
22142
+ fn.async = expr.isAsync ?? false;
22143
+ return fn;
22144
+ },
22145
+ localDeclared
22146
+ )
21806
22147
  );
21807
22148
  }
21808
22149
  case "AssignmentExpression":
@@ -21936,10 +22277,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21936
22277
  case "AwaitExpression":
21937
22278
  return t2.awaitExpression(lowerExpression(expr.argument, ctx));
21938
22279
  case "NewExpression":
21939
- return t2.newExpression(
21940
- lowerExpression(expr.callee, ctx),
21941
- expr.arguments.map((a) => lowerExpression(a, ctx))
21942
- );
22280
+ return t2.newExpression(lowerExpression(expr.callee, ctx), lowerCallArguments(expr.arguments));
21943
22281
  case "SequenceExpression":
21944
22282
  return t2.sequenceExpression(expr.expressions.map((e) => lowerExpression(e, ctx)));
21945
22283
  case "YieldExpression":
@@ -21950,7 +22288,7 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
21950
22288
  case "OptionalCallExpression":
21951
22289
  return t2.optionalCallExpression(
21952
22290
  lowerExpression(expr.callee, ctx),
21953
- expr.arguments.map((a) => lowerExpression(a, ctx)),
22291
+ lowerCallArguments(expr.arguments),
21954
22292
  expr.optional
21955
22293
  );
21956
22294
  case "TaggedTemplateExpression":
@@ -22082,26 +22420,17 @@ function lowerJSXElement(jsx, ctx) {
22082
22420
  ]);
22083
22421
  }
22084
22422
  ctx.helpersUsed.add("createElement");
22085
- const propsObj = buildPropsObject(jsx.attributes, ctx);
22086
22423
  const children = jsx.children.map((c) => lowerJSXChild(c, ctx));
22424
+ const propsExpr = buildPropsExpression(jsx.attributes, children, ctx, {
22425
+ lowerDomExpression,
22426
+ lowerTrackedExpression,
22427
+ expressionUsesTracked,
22428
+ deSSAVarName
22429
+ });
22087
22430
  const componentRef = typeof jsx.tagName === "string" ? t2.identifier(jsx.tagName) : lowerExpression(jsx.tagName, ctx);
22088
- const propsWithChildren = [];
22089
- if (propsObj && t2.isObjectExpression(propsObj)) {
22090
- propsWithChildren.push(...propsObj.properties);
22091
- }
22092
- if (children.length === 1 && children[0]) {
22093
- propsWithChildren.push(t2.objectProperty(t2.identifier("children"), children[0]));
22094
- } else if (children.length > 1) {
22095
- propsWithChildren.push(
22096
- t2.objectProperty(t2.identifier("children"), t2.arrayExpression(children))
22097
- );
22098
- }
22099
22431
  return t2.objectExpression([
22100
22432
  t2.objectProperty(t2.identifier("type"), componentRef),
22101
- t2.objectProperty(
22102
- t2.identifier("props"),
22103
- propsWithChildren.length > 0 ? t2.objectExpression(propsWithChildren) : t2.nullLiteral()
22104
- )
22433
+ t2.objectProperty(t2.identifier("props"), propsExpr ?? t2.nullLiteral())
22105
22434
  ]);
22106
22435
  }
22107
22436
  const useFineGrainedDom = !ctx.noMemo;
@@ -23854,98 +24183,6 @@ function lowerJSXChild(child, ctx) {
23854
24183
  return applyRegionMetadataToExpression(lowerExpression(child.value, ctx), ctx);
23855
24184
  }
23856
24185
  }
23857
- function buildPropsObject(attributes, ctx) {
23858
- const { t: t2 } = ctx;
23859
- const prevPropsContext = ctx.inPropsContext;
23860
- ctx.inPropsContext = true;
23861
- try {
23862
- if (attributes.length === 0) return null;
23863
- const properties = [];
23864
- const spreads = [];
23865
- const toPropKey = (name) => /^[a-zA-Z_$][\w$]*$/.test(name) ? t2.identifier(name) : t2.stringLiteral(name);
23866
- const isAccessorName = (name) => (ctx.memoVars?.has(name) ?? false) || (ctx.signalVars?.has(name) ?? false) || (ctx.aliasVars?.has(name) ?? false);
23867
- const wrapAccessorSource = (node) => {
23868
- if (t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.arguments.length === 0) {
23869
- const baseName2 = deSSAVarName(node.callee.name);
23870
- if (isAccessorName(baseName2)) {
23871
- return t2.arrowFunctionExpression([], node);
23872
- }
23873
- }
23874
- if (t2.isIdentifier(node)) {
23875
- const baseName2 = deSSAVarName(node.name);
23876
- if (isAccessorName(baseName2)) {
23877
- return t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseName2), []));
23878
- }
23879
- }
23880
- return node;
23881
- };
23882
- for (const attr of attributes) {
23883
- if (attr.isSpread && attr.spreadExpr) {
23884
- let spreadExpr = lowerDomExpression(attr.spreadExpr, ctx);
23885
- if (t2.isCallExpression(spreadExpr)) {
23886
- const callExpr = spreadExpr;
23887
- const rewrittenArgs = callExpr.arguments.map(
23888
- (arg) => t2.isExpression(arg) ? wrapAccessorSource(arg) : arg
23889
- );
23890
- if (rewrittenArgs.some((arg, idx) => arg !== callExpr.arguments[idx])) {
23891
- spreadExpr = t2.callExpression(callExpr.callee, rewrittenArgs);
23892
- }
23893
- }
23894
- spreadExpr = wrapAccessorSource(spreadExpr);
23895
- spreads.push(t2.spreadElement(spreadExpr));
23896
- } else if (attr.value) {
23897
- const isFunctionLike = attr.value.kind === "ArrowFunction" || attr.value.kind === "FunctionExpression";
23898
- const prevPropsCtx = ctx.inPropsContext;
23899
- if (isFunctionLike) {
23900
- ctx.inPropsContext = false;
23901
- }
23902
- const lowered = lowerDomExpression(attr.value, ctx);
23903
- if (isFunctionLike) {
23904
- ctx.inPropsContext = prevPropsCtx;
23905
- }
23906
- const baseIdent = attr.value.kind === "Identifier" ? deSSAVarName(attr.value.name) : void 0;
23907
- const isAccessorBase = baseIdent && ((ctx.memoVars?.has(baseIdent) ?? false) || (ctx.signalVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false));
23908
- const isStoreBase = baseIdent ? ctx.storeVars?.has(baseIdent) ?? false : false;
23909
- const alreadyGetter = isFunctionLike || (baseIdent ? isStoreBase || (ctx.memoVars?.has(baseIdent) ?? false) || (ctx.aliasVars?.has(baseIdent) ?? false) : false);
23910
- const usesTracked = (!ctx.nonReactiveScopeDepth || ctx.nonReactiveScopeDepth === 0) && expressionUsesTracked(attr.value, ctx) && !alreadyGetter;
23911
- const trackedExpr = usesTracked ? lowerTrackedExpression(attr.value, ctx) : null;
23912
- const useMemoProp = usesTracked && trackedExpr && t2.isExpression(trackedExpr) && !t2.isIdentifier(trackedExpr) && !t2.isMemberExpression(trackedExpr) && !t2.isLiteral(trackedExpr);
23913
- const valueExpr = !isFunctionLike && isAccessorBase && baseIdent ? (() => {
23914
- ctx.helpersUsed.add("propGetter");
23915
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
23916
- t2.arrowFunctionExpression([], t2.callExpression(t2.identifier(baseIdent), []))
23917
- ]);
23918
- })() : usesTracked && t2.isExpression(lowered) ? (() => {
23919
- if (useMemoProp) {
23920
- ctx.helpersUsed.add("useProp");
23921
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
23922
- t2.arrowFunctionExpression(
23923
- [],
23924
- trackedExpr ?? lowered
23925
- )
23926
- ]);
23927
- }
23928
- ctx.helpersUsed.add("propGetter");
23929
- return t2.callExpression(t2.identifier(RUNTIME_ALIASES.propGetter), [
23930
- t2.arrowFunctionExpression(
23931
- [],
23932
- trackedExpr ?? lowered
23933
- )
23934
- ]);
23935
- })() : lowered;
23936
- properties.push(t2.objectProperty(toPropKey(attr.name), valueExpr));
23937
- } else {
23938
- properties.push(t2.objectProperty(toPropKey(attr.name), t2.booleanLiteral(true)));
23939
- }
23940
- }
23941
- if (spreads.length > 0) {
23942
- return t2.objectExpression([...spreads, ...properties]);
23943
- }
23944
- return t2.objectExpression(properties);
23945
- } finally {
23946
- ctx.inPropsContext = prevPropsContext;
23947
- }
23948
- }
23949
24186
  function isDOMProperty(name) {
23950
24187
  return ["value", "checked", "selected", "disabled", "readOnly", "multiple", "muted"].includes(
23951
24188
  name
@@ -23962,6 +24199,8 @@ function lowerHIRWithRegions(program, t2, options) {
23962
24199
  let topLevelCtxInjected = false;
23963
24200
  const emittedFunctionNames = /* @__PURE__ */ new Set();
23964
24201
  const originalBody = program.originalBody ?? [];
24202
+ ctx.moduleDeclaredNames = collectDeclaredNames(originalBody, t2);
24203
+ ctx.moduleRuntimeNames = collectRuntimeImportNames(originalBody, t2);
23965
24204
  for (const stmt of originalBody) {
23966
24205
  if (t2.isVariableDeclaration(stmt)) {
23967
24206
  for (const decl of stmt.declarations) {
@@ -24359,6 +24598,12 @@ function lowerFunctionWithRegions(fn, ctx) {
24359
24598
  const functionShadowed = new Set(prevShadowed ?? []);
24360
24599
  shadowedParams.forEach((n) => functionShadowed.add(n));
24361
24600
  ctx.shadowedNames = functionShadowed;
24601
+ const prevLocalDeclared = ctx.localDeclaredNames;
24602
+ const localDeclared = new Set(prevLocalDeclared ?? []);
24603
+ for (const name of collectLocalDeclaredNames(fn.params, fn.blocks, t2)) {
24604
+ localDeclared.add(name);
24605
+ }
24606
+ ctx.localDeclaredNames = localDeclared;
24362
24607
  const prevExternalTracked = ctx.externalTracked;
24363
24608
  const inheritedTracked = new Set(ctx.trackedVars);
24364
24609
  ctx.externalTracked = inheritedTracked;
@@ -24440,16 +24685,75 @@ function lowerFunctionWithRegions(fn, ctx) {
24440
24685
  const stmts = [];
24441
24686
  const excludeKeys = [];
24442
24687
  let supported = true;
24443
- let usesUseProp = false;
24688
+ let usesProp = false;
24444
24689
  let usesPropsRest = false;
24445
24690
  let warnedNested = false;
24691
+ const reportedPatternNodes = /* @__PURE__ */ new Set();
24692
+ const reportPatternDiagnostic = (node, code) => {
24693
+ if (reportedPatternNodes.has(node)) return;
24694
+ reportedPatternNodes.add(node);
24695
+ reportDiagnostic(ctx, code, node);
24696
+ };
24697
+ const reportPropsPatternIssues = (objectPattern, allowRest) => {
24698
+ for (const prop of objectPattern.properties) {
24699
+ if (t2.isObjectProperty(prop)) {
24700
+ if (prop.computed) {
24701
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24702
+ continue;
24703
+ }
24704
+ 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;
24705
+ if (!keyName) {
24706
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24707
+ continue;
24708
+ }
24709
+ const value = prop.value;
24710
+ if (t2.isIdentifier(value)) {
24711
+ continue;
24712
+ }
24713
+ if (t2.isObjectPattern(value)) {
24714
+ reportPropsPatternIssues(value, false);
24715
+ continue;
24716
+ }
24717
+ if (t2.isAssignmentPattern(value)) {
24718
+ if (t2.isIdentifier(value.left)) {
24719
+ continue;
24720
+ }
24721
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24722
+ continue;
24723
+ }
24724
+ if (t2.isArrayPattern(value)) {
24725
+ const hasRest = value.elements.some((el) => t2.isRestElement(el));
24726
+ reportPatternDiagnostic(
24727
+ value,
24728
+ hasRest ? "FICT-P002" /* FICT_P002 */ : "FICT-P001" /* FICT_P001 */
24729
+ );
24730
+ continue;
24731
+ }
24732
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24733
+ continue;
24734
+ }
24735
+ if (t2.isRestElement(prop)) {
24736
+ if (!allowRest || !t2.isIdentifier(prop.argument)) {
24737
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24738
+ }
24739
+ continue;
24740
+ }
24741
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24742
+ }
24743
+ };
24446
24744
  const memberExprForKey = (base, key) => t2.memberExpression(base, t2.identifier(key), false);
24447
24745
  const buildDestructure = (objectPattern, baseExpr, allowRest) => {
24448
24746
  for (const prop of objectPattern.properties) {
24449
- if (t2.isObjectProperty(prop) && !prop.computed) {
24747
+ if (t2.isObjectProperty(prop)) {
24748
+ if (prop.computed) {
24749
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24750
+ supported = false;
24751
+ warnedNested = true;
24752
+ break;
24753
+ }
24450
24754
  const keyName = t2.isIdentifier(prop.key) ? prop.key.name : t2.isStringLiteral(prop.key) ? prop.key.value : t2.isNumericLiteral(prop.key) ? String(prop.key.value) : null;
24451
24755
  if (!keyName) {
24452
- reportDiagnostic(ctx, "FICT-P003" /* FICT_P003 */, prop);
24756
+ reportPatternDiagnostic(prop, "FICT-P003" /* FICT_P003 */);
24453
24757
  supported = false;
24454
24758
  warnedNested = true;
24455
24759
  break;
@@ -24460,16 +24764,16 @@ function lowerFunctionWithRegions(fn, ctx) {
24460
24764
  const member = memberExprForKey(baseExpr, keyName);
24461
24765
  const value = prop.value;
24462
24766
  if (t2.isIdentifier(value)) {
24463
- const shouldUseProp = !calledIdentifiers.has(value.name);
24464
- if (shouldUseProp) {
24465
- usesUseProp = true;
24767
+ const shouldWrapProp = !calledIdentifiers.has(value.name);
24768
+ if (shouldWrapProp) {
24769
+ usesProp = true;
24466
24770
  propsPlanAliases.add(value.name);
24467
24771
  }
24468
24772
  stmts.push(
24469
24773
  t2.variableDeclaration("const", [
24470
24774
  t2.variableDeclarator(
24471
24775
  t2.identifier(value.name),
24472
- shouldUseProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24776
+ shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24473
24777
  t2.arrowFunctionExpression([], member)
24474
24778
  ]) : member
24475
24779
  )
@@ -24482,26 +24786,44 @@ function lowerFunctionWithRegions(fn, ctx) {
24482
24786
  if (!supported) break;
24483
24787
  continue;
24484
24788
  }
24485
- if (t2.isAssignmentPattern(value) && t2.isIdentifier(value.left)) {
24486
- const shouldUseProp = !calledIdentifiers.has(value.left.name);
24487
- if (shouldUseProp) {
24488
- usesUseProp = true;
24489
- propsPlanAliases.add(value.left.name);
24789
+ if (t2.isAssignmentPattern(value)) {
24790
+ if (t2.isIdentifier(value.left)) {
24791
+ const shouldWrapProp = !calledIdentifiers.has(value.left.name);
24792
+ if (shouldWrapProp) {
24793
+ usesProp = true;
24794
+ propsPlanAliases.add(value.left.name);
24795
+ }
24796
+ const baseInit = t2.logicalExpression("??", member, value.right);
24797
+ const init = shouldWrapProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.prop), [
24798
+ t2.arrowFunctionExpression([], baseInit)
24799
+ ]) : baseInit;
24800
+ stmts.push(
24801
+ t2.variableDeclaration("const", [
24802
+ t2.variableDeclarator(t2.identifier(value.left.name), init)
24803
+ ])
24804
+ );
24805
+ continue;
24490
24806
  }
24491
- const baseInit = t2.logicalExpression("??", member, value.right);
24492
- const init = shouldUseProp ? t2.callExpression(t2.identifier(RUNTIME_ALIASES.useProp), [
24493
- t2.arrowFunctionExpression([], baseInit)
24494
- ]) : baseInit;
24495
- stmts.push(
24496
- t2.variableDeclaration("const", [
24497
- t2.variableDeclarator(t2.identifier(value.left.name), init)
24498
- ])
24807
+ supported = false;
24808
+ if (!warnedNested) {
24809
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24810
+ warnedNested = true;
24811
+ }
24812
+ break;
24813
+ }
24814
+ if (t2.isArrayPattern(value)) {
24815
+ const hasRest = value.elements.some((el) => t2.isRestElement(el));
24816
+ reportPatternDiagnostic(
24817
+ value,
24818
+ hasRest ? "FICT-P002" /* FICT_P002 */ : "FICT-P001" /* FICT_P001 */
24499
24819
  );
24500
- continue;
24820
+ supported = false;
24821
+ warnedNested = true;
24822
+ break;
24501
24823
  }
24502
24824
  supported = false;
24503
24825
  if (!warnedNested) {
24504
- reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24826
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24505
24827
  warnedNested = true;
24506
24828
  }
24507
24829
  break;
@@ -24522,18 +24844,19 @@ function lowerFunctionWithRegions(fn, ctx) {
24522
24844
  } else {
24523
24845
  supported = false;
24524
24846
  if (!warnedNested) {
24525
- reportDiagnostic(ctx, "FICT-P004" /* FICT_P004 */, prop);
24847
+ reportPatternDiagnostic(prop, "FICT-P004" /* FICT_P004 */);
24526
24848
  warnedNested = true;
24527
24849
  }
24528
24850
  break;
24529
24851
  }
24530
24852
  }
24531
24853
  };
24854
+ reportPropsPatternIssues(pattern, true);
24532
24855
  buildDestructure(pattern, t2.identifier("__props"), true);
24533
24856
  if (supported) {
24534
24857
  propsDestructurePlan = {
24535
24858
  statements: stmts,
24536
- usesUseProp,
24859
+ usesProp,
24537
24860
  usesPropsRest
24538
24861
  };
24539
24862
  propsPlanAliases.forEach((name) => {
@@ -24575,6 +24898,7 @@ function lowerFunctionWithRegions(fn, ctx) {
24575
24898
  if (!hasJSX && !hasTrackedValues) {
24576
24899
  ctx.needsCtx = prevNeedsCtx;
24577
24900
  ctx.shadowedNames = prevShadowed;
24901
+ ctx.localDeclaredNames = prevLocalDeclared;
24578
24902
  ctx.trackedVars = prevTracked;
24579
24903
  ctx.externalTracked = prevExternalTracked;
24580
24904
  ctx.signalVars = prevSignalVars;
@@ -24627,8 +24951,8 @@ function lowerFunctionWithRegions(fn, ctx) {
24627
24951
  finalParams = [t2.identifier("__props")];
24628
24952
  const pattern = rawParam.type === "AssignmentPattern" ? rawParam.left : rawParam;
24629
24953
  if (propsDestructurePlan) {
24630
- if (propsDestructurePlan.usesUseProp) {
24631
- ctx.helpersUsed.add("useProp");
24954
+ if (propsDestructurePlan.usesProp) {
24955
+ ctx.helpersUsed.add("prop");
24632
24956
  }
24633
24957
  if (propsDestructurePlan.usesPropsRest) {
24634
24958
  ctx.helpersUsed.add("propsRest");
@@ -24657,6 +24981,7 @@ function lowerFunctionWithRegions(fn, ctx) {
24657
24981
  );
24658
24982
  ctx.needsCtx = prevNeedsCtx;
24659
24983
  ctx.shadowedNames = prevShadowed;
24984
+ ctx.localDeclaredNames = prevLocalDeclared;
24660
24985
  ctx.trackedVars = prevTracked;
24661
24986
  ctx.externalTracked = prevExternalTracked;
24662
24987
  ctx.signalVars = prevSignalVars;
@@ -25116,8 +25441,10 @@ function createHIREntrypointVisitor(t2, options) {
25116
25441
  const fileName = path.hub?.file?.opts?.filename || "<unknown>";
25117
25442
  const comments = path.hub?.file?.ast?.comments || [];
25118
25443
  const suppressions = parseSuppressions(comments);
25119
- const warn = createWarningDispatcher(options.onWarn, suppressions);
25120
- const optionsWithWarnings = { ...options, onWarn: warn };
25444
+ const dev = options.dev !== false;
25445
+ const warn = dev ? createWarningDispatcher(options.onWarn, suppressions) : () => {
25446
+ };
25447
+ const optionsWithWarnings = dev ? { ...options, onWarn: warn } : { ...options, onWarn: void 0 };
25121
25448
  const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
25122
25449
  const getFunctionName = (fnPath) => {
25123
25450
  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;
@@ -25373,6 +25700,18 @@ function createHIREntrypointVisitor(t2, options) {
25373
25700
  },
25374
25701
  CallExpression(callPath) {
25375
25702
  if (isStateCall(callPath.node, t2)) {
25703
+ const parentPath = callPath.parentPath;
25704
+ const isVariableDeclarator = parentPath?.isVariableDeclarator() && parentPath.node.init === callPath.node;
25705
+ if (!isVariableDeclarator) {
25706
+ throw callPath.buildCodeFrameError(
25707
+ "$state() must be assigned directly to a variable (e.g. let count = $state(0)). For object state, consider using $store from fict/plus."
25708
+ );
25709
+ }
25710
+ if (!t2.isIdentifier(parentPath.node.id)) {
25711
+ throw callPath.buildCodeFrameError(
25712
+ "Destructuring $state is not supported. Use a simple identifier."
25713
+ );
25714
+ }
25376
25715
  const ownerComponent = callPath.getFunctionParent();
25377
25716
  if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
25378
25717
  throw callPath.buildCodeFrameError(
@@ -25565,7 +25904,9 @@ function createHIREntrypointVisitor(t2, options) {
25565
25904
  }
25566
25905
  });
25567
25906
  }
25568
- runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25907
+ if (dev) {
25908
+ runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
25909
+ }
25569
25910
  const fileAst = t2.file(path.node);
25570
25911
  const hir = buildHIR(fileAst);
25571
25912
  const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
@@ -25585,7 +25926,8 @@ var createFictPlugin = declare(
25585
25926
  const t2 = api.types;
25586
25927
  const normalizedOptions = {
25587
25928
  ...options,
25588
- fineGrainedDom: options.fineGrainedDom ?? true
25929
+ fineGrainedDom: options.fineGrainedDom ?? true,
25930
+ dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
25589
25931
  };
25590
25932
  return {
25591
25933
  name: "fict-compiler-hir",