@fictjs/compiler 0.4.0 → 0.5.1

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
@@ -14135,6 +14135,9 @@ var RUNTIME_HELPERS = {
14135
14135
  conditional: "createConditional",
14136
14136
  keyedList: "createKeyedList",
14137
14137
  insert: "insert",
14138
+ insertBetween: "insertBetween",
14139
+ resolvePath: "resolvePath",
14140
+ getSlotEnd: "getSlotEnd",
14138
14141
  onDestroy: "onDestroy",
14139
14142
  bindText: "bindText",
14140
14143
  bindAttribute: "bindAttribute",
@@ -14146,7 +14149,18 @@ var RUNTIME_HELPERS = {
14146
14149
  bindRef: "bindRef",
14147
14150
  toNodeArray: "toNodeArray",
14148
14151
  template: "template",
14149
- delegateEvents: "delegateEvents"
14152
+ delegateEvents: "delegateEvents",
14153
+ useLexicalScope: "__fictUseLexicalScope",
14154
+ getScopeProps: "__fictGetScopeProps",
14155
+ qrl: "__fictQrl",
14156
+ getSSRScope: "__fictGetSSRScope",
14157
+ ensureScope: "__fictEnsureScope",
14158
+ prepareContext: "__fictPrepareContext",
14159
+ enterHydration: "__fictEnterHydration",
14160
+ exitHydration: "__fictExitHydration",
14161
+ domRender: "render",
14162
+ hydrateComponent: "hydrateComponent",
14163
+ registerResume: "__fictRegisterResume"
14150
14164
  };
14151
14165
  var RUNTIME_ALIASES = {
14152
14166
  signal: "createSignal",
@@ -14171,6 +14185,9 @@ var RUNTIME_ALIASES = {
14171
14185
  conditional: "createConditional",
14172
14186
  keyedList: "createKeyedList",
14173
14187
  insert: "insert",
14188
+ insertBetween: "insertBetween",
14189
+ resolvePath: "resolvePath",
14190
+ getSlotEnd: "getSlotEnd",
14174
14191
  onDestroy: "onDestroy",
14175
14192
  bindText: "bindText",
14176
14193
  bindAttribute: "bindAttribute",
@@ -14182,7 +14199,18 @@ var RUNTIME_ALIASES = {
14182
14199
  bindRef: "bindRef",
14183
14200
  toNodeArray: "toNodeArray",
14184
14201
  template: "template",
14185
- delegateEvents: "delegateEvents"
14202
+ delegateEvents: "delegateEvents",
14203
+ useLexicalScope: "__fictUseLexicalScope",
14204
+ getScopeProps: "__fictGetScopeProps",
14205
+ qrl: "__fictQrl",
14206
+ getSSRScope: "__fictGetSSRScope",
14207
+ ensureScope: "__fictEnsureScope",
14208
+ prepareContext: "__fictPrepareContext",
14209
+ enterHydration: "__fictEnterHydration",
14210
+ exitHydration: "__fictExitHydration",
14211
+ domRender: "render",
14212
+ hydrateComponent: "hydrateComponent",
14213
+ registerResume: "__fictRegisterResume"
14186
14214
  };
14187
14215
  var DelegatedEvents = /* @__PURE__ */ new Set([...DelegatedEventNames]);
14188
14216
  var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
@@ -14533,6 +14561,9 @@ function parseFictReturnAnnotation(node) {
14533
14561
  if (content === "'memo'" || content === '"memo"') {
14534
14562
  return { directAccessor: "memo" };
14535
14563
  }
14564
+ if (/^\{\s*\}$/.test(content)) {
14565
+ return { objectProps: /* @__PURE__ */ new Map() };
14566
+ }
14536
14567
  const objectMatch = content.match(/^\{([^}]+)\}$/);
14537
14568
  if (objectMatch) {
14538
14569
  const objectProps = /* @__PURE__ */ new Map();
@@ -16092,6 +16123,7 @@ function convertExpression(node, options) {
16092
16123
  const arrow = {
16093
16124
  kind: "ArrowFunction",
16094
16125
  params: nested.params,
16126
+ rawParams: nested.rawParams ?? node.params,
16095
16127
  body: nested.blocks,
16096
16128
  isExpression: false,
16097
16129
  isAsync: node.async,
@@ -16105,6 +16137,7 @@ function convertExpression(node, options) {
16105
16137
  params: node.params.map(
16106
16138
  (p) => t.isPattern(p) ? extractIdentifiersFromPattern(p) : t.isIdentifier(p) ? [{ kind: "Identifier", name: p.name }] : []
16107
16139
  ).flat(),
16140
+ rawParams: node.params,
16108
16141
  body: convertExpression(node.body),
16109
16142
  isExpression: true,
16110
16143
  isAsync: node.async,
@@ -16126,6 +16159,7 @@ function convertExpression(node, options) {
16126
16159
  kind: "FunctionExpression",
16127
16160
  name: node.id?.name ?? "",
16128
16161
  params: nested.params,
16162
+ rawParams: nested.rawParams ?? node.params,
16129
16163
  body: nested.blocks,
16130
16164
  isAsync: node.async,
16131
16165
  reactiveScope: options?.reactiveScope,
@@ -16362,6 +16396,9 @@ function convertJSXMemberExpr(node) {
16362
16396
  };
16363
16397
  }
16364
16398
 
16399
+ // src/ir/codegen.ts
16400
+ import { pathToFileURL } from "url";
16401
+
16365
16402
  // src/fine-grained-dom.ts
16366
16403
  function normalizeDependencyKey(name) {
16367
16404
  return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
@@ -21161,9 +21198,14 @@ function instructionToStatement(instr, t4, declaredVars, ctx, _buildMemoCall) {
21161
21198
  declaredVars.add(baseName2);
21162
21199
  if (treatAsTracked && !isDestructuringTemp) {
21163
21200
  if (isStateCall2) {
21164
- return t4.variableDeclaration(normalizedDecl, [
21165
- t4.variableDeclarator(t4.identifier(baseName2), lowerAssignedValue(true))
21166
- ]);
21201
+ ctx.currentAssignmentName = baseName2;
21202
+ try {
21203
+ return t4.variableDeclaration(normalizedDecl, [
21204
+ t4.variableDeclarator(t4.identifier(baseName2), lowerAssignedValue(true))
21205
+ ]);
21206
+ } finally {
21207
+ ctx.currentAssignmentName = void 0;
21208
+ }
21167
21209
  }
21168
21210
  if (dependsOnTracked) {
21169
21211
  if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
@@ -22086,7 +22128,17 @@ function createCodegenContext(t4) {
22086
22128
  hookReturnInfo: /* @__PURE__ */ new Map(),
22087
22129
  hoistedTemplates: /* @__PURE__ */ new Map(),
22088
22130
  hoistedTemplateStatements: [],
22089
- delegatedEventsUsed: /* @__PURE__ */ new Set()
22131
+ hoistedResumableStatements: [],
22132
+ resumableHandlerCounter: 0,
22133
+ resumableComponentCounter: 0,
22134
+ resumableComponents: /* @__PURE__ */ new Map(),
22135
+ resumableEnabled: false,
22136
+ autoExtractEnabled: false,
22137
+ autoExtractThreshold: 3,
22138
+ delegatedEventsUsed: /* @__PURE__ */ new Set(),
22139
+ componentFunctionDefs: /* @__PURE__ */ new Map(),
22140
+ hoistedFunctionDepCounter: 0,
22141
+ hoistedFunctionDepNames: /* @__PURE__ */ new Map()
22090
22142
  };
22091
22143
  }
22092
22144
  function withGetterCache(ctx, fn) {
@@ -22992,6 +23044,51 @@ function computeReactiveAccessors(fn, ctx) {
22992
23044
  function genTemp(ctx, prefix = "tmp") {
22993
23045
  return ctx.t.identifier(`__${prefix}_${ctx.tempCounter++}`);
22994
23046
  }
23047
+ function renameIdentifiersInExpr(expr, renames, _t) {
23048
+ const cloned = JSON.parse(JSON.stringify(expr));
23049
+ function visit(node) {
23050
+ if (!node || typeof node !== "object") return;
23051
+ const n = node;
23052
+ if (n.type === "Identifier" && typeof n.name === "string") {
23053
+ const newName = renames.get(n.name);
23054
+ if (newName) {
23055
+ n.name = newName;
23056
+ }
23057
+ }
23058
+ for (const key of Object.keys(n)) {
23059
+ if (key === "loc" || key === "start" || key === "end" || key === "extra" || key === "comments" || key === "leadingComments" || key === "trailingComments") {
23060
+ continue;
23061
+ }
23062
+ const value = n[key];
23063
+ if (Array.isArray(value)) {
23064
+ for (const item of value) {
23065
+ visit(item);
23066
+ }
23067
+ } else if (value && typeof value === "object") {
23068
+ visit(value);
23069
+ }
23070
+ }
23071
+ }
23072
+ visit(cloned);
23073
+ return cloned;
23074
+ }
23075
+ function genModuleUrlExpr(ctx) {
23076
+ const { t: t4 } = ctx;
23077
+ const filename = ctx.options?.filename;
23078
+ if (filename) {
23079
+ let fileUrl;
23080
+ if (filename.startsWith("file://")) {
23081
+ fileUrl = filename;
23082
+ } else {
23083
+ fileUrl = pathToFileURL(filename).href;
23084
+ }
23085
+ return t4.stringLiteral(fileUrl);
23086
+ }
23087
+ return t4.memberExpression(
23088
+ t4.metaProperty(t4.identifier("import"), t4.identifier("meta")),
23089
+ t4.identifier("url")
23090
+ );
23091
+ }
22995
23092
  function extractKeyFromAttributes(attributes) {
22996
23093
  for (const attr of attributes) {
22997
23094
  if (attr.name === "key" && attr.value) {
@@ -23115,6 +23212,26 @@ function lowerInstruction(instr, ctx) {
23115
23212
  ctx.memoVars?.add(baseName2);
23116
23213
  }
23117
23214
  }
23215
+ if (declKind) {
23216
+ const initKind = getReactiveCallKind(instr.value, ctx);
23217
+ if (initKind === "signal") {
23218
+ ctx.signalVars?.add(baseName2);
23219
+ ctx.trackedVars.add(baseName2);
23220
+ ctx.currentAssignmentName = baseName2;
23221
+ const loweredValue = (() => {
23222
+ try {
23223
+ return lowerTrackedExpression(instr.value, ctx);
23224
+ } finally {
23225
+ ctx.currentAssignmentName = void 0;
23226
+ }
23227
+ })();
23228
+ return applyLoc(
23229
+ t4.variableDeclaration(declKind, [
23230
+ t4.variableDeclarator(t4.identifier(baseName2), loweredValue)
23231
+ ])
23232
+ );
23233
+ }
23234
+ }
23118
23235
  if (ctx.signalVars?.has(baseName2)) {
23119
23236
  ctx.currentAssignmentName = baseName2;
23120
23237
  const loweredValue = (() => {
@@ -23776,7 +23893,13 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
23776
23893
  })),
23777
23894
  entryBlock: fn.blocks[0]?.id ?? 0
23778
23895
  };
23779
- const declared = new Set(paramIds.map((p) => p.name));
23896
+ const declared = /* @__PURE__ */ new Set();
23897
+ for (const p of paramIds) {
23898
+ const ids = t4.getBindingIdentifiers(p);
23899
+ for (const name of Object.keys(ids)) {
23900
+ declared.add(name);
23901
+ }
23902
+ }
23780
23903
  return lowerStructuredNodeWithoutRegions(structured, t4, ctx, declared);
23781
23904
  } catch {
23782
23905
  return lowerBlocksToStatements(blocks);
@@ -23840,23 +23963,23 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
23840
23963
  case "MetaProperty":
23841
23964
  return t4.metaProperty(t4.identifier(expr.meta.name), t4.identifier(expr.property.name));
23842
23965
  case "CallExpression": {
23843
- if (expr.callee.kind === "Identifier" && expr.callee.name === "$state") {
23966
+ const stateCalleeNameRaw = expr.callee.kind === "Identifier" ? expr.callee.name : null;
23967
+ const stateCalleeName = stateCalleeNameRaw ? deSSAVarName(stateCalleeNameRaw) : null;
23968
+ if (stateCalleeName && ctx.stateMacroNames?.has(stateCalleeName)) {
23844
23969
  const args = lowerCallArguments(expr.arguments);
23845
23970
  const includeDevtools = ctx.options?.dev !== false;
23846
- if (includeDevtools) {
23847
- const options = [];
23848
- if (ctx.currentAssignmentName) {
23849
- options.push(
23850
- t4.objectProperty(t4.identifier("name"), t4.stringLiteral(ctx.currentAssignmentName))
23851
- );
23852
- }
23853
- if (expr.loc) {
23854
- const source = `${ctx.options?.filename ?? ""}:${expr.loc.start.line}:${expr.loc.start.column}`;
23855
- options.push(t4.objectProperty(t4.identifier("devToolsSource"), t4.stringLiteral(source)));
23856
- }
23857
- if (options.length > 0) {
23858
- args.push(t4.objectExpression(options));
23859
- }
23971
+ const options = [];
23972
+ if (ctx.currentAssignmentName) {
23973
+ options.push(
23974
+ t4.objectProperty(t4.identifier("name"), t4.stringLiteral(ctx.currentAssignmentName))
23975
+ );
23976
+ }
23977
+ if (includeDevtools && expr.loc) {
23978
+ const source = `${ctx.options?.filename ?? ""}:${expr.loc.start.line}:${expr.loc.start.column}`;
23979
+ options.push(t4.objectProperty(t4.identifier("devToolsSource"), t4.stringLiteral(source)));
23980
+ }
23981
+ if (options.length > 0) {
23982
+ args.push(t4.objectExpression(options));
23860
23983
  }
23861
23984
  if (ctx.inModule) {
23862
23985
  ctx.helpersUsed.add("signal");
@@ -24077,7 +24200,12 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
24077
24200
  case "ArrowFunction": {
24078
24201
  const reactiveLowered = lowerReactiveScopeExpression(expr);
24079
24202
  if (reactiveLowered) return reactiveLowered;
24080
- const paramIds = mapParams(expr.params);
24203
+ const useRawParams = expr.rawParams && expr.rawParams.length > 0 && expr.rawParams.every(
24204
+ (param) => t4.isIdentifier(param) || t4.isRestElement(param) && t4.isIdentifier(param.argument)
24205
+ );
24206
+ const paramIds = useRawParams ? expr.rawParams.map(
24207
+ (param) => t4.cloneNode(param, true)
24208
+ ) : mapParams(expr.params);
24081
24209
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
24082
24210
  const localDeclared = collectLocalDeclaredNames(
24083
24211
  expr.params,
@@ -24125,7 +24253,12 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
24125
24253
  case "FunctionExpression": {
24126
24254
  const reactiveLowered = lowerReactiveScopeExpression(expr);
24127
24255
  if (reactiveLowered) return reactiveLowered;
24128
- const paramIds = mapParams(expr.params);
24256
+ const useRawParams = expr.rawParams && expr.rawParams.length > 0 && expr.rawParams.every(
24257
+ (param) => t4.isIdentifier(param) || t4.isRestElement(param) && t4.isIdentifier(param.argument)
24258
+ );
24259
+ const paramIds = useRawParams ? expr.rawParams.map(
24260
+ (param) => t4.cloneNode(param, true)
24261
+ ) : mapParams(expr.params);
24129
24262
  const shadowed = new Set(expr.params.map((p) => deSSAVarName(p.name)));
24130
24263
  const localDeclared = collectLocalDeclaredNames(expr.params, expr.body, t4);
24131
24264
  return withNonReactiveScope(
@@ -25010,17 +25143,280 @@ function resolveNamespaceContext(tagName, parentNamespace) {
25010
25143
  if (tagName === "foreignObject" && parentNamespace === "svg") return null;
25011
25144
  return parentNamespace;
25012
25145
  }
25146
+ function countExpressionNodes(expr) {
25147
+ if (!expr) return 0;
25148
+ let count = 1;
25149
+ switch (expr.kind) {
25150
+ case "Literal":
25151
+ return 1;
25152
+ case "Identifier":
25153
+ return 1;
25154
+ case "BinaryExpression":
25155
+ case "LogicalExpression":
25156
+ count += countExpressionNodes(expr.left);
25157
+ count += countExpressionNodes(expr.right);
25158
+ return count;
25159
+ case "UnaryExpression":
25160
+ count += countExpressionNodes(expr.argument);
25161
+ return count;
25162
+ case "ConditionalExpression":
25163
+ count += countExpressionNodes(expr.test);
25164
+ count += countExpressionNodes(expr.consequent);
25165
+ count += countExpressionNodes(expr.alternate);
25166
+ return count;
25167
+ case "CallExpression":
25168
+ count += countExpressionNodes(expr.callee);
25169
+ for (const arg of expr.arguments) {
25170
+ count += countExpressionNodes(arg);
25171
+ }
25172
+ return count;
25173
+ case "MemberExpression":
25174
+ count += countExpressionNodes(expr.object);
25175
+ if (expr.computed && expr.property) {
25176
+ count += countExpressionNodes(expr.property);
25177
+ }
25178
+ return count;
25179
+ case "ArrayExpression":
25180
+ for (const elem of expr.elements) {
25181
+ if (elem) count += countExpressionNodes(elem);
25182
+ }
25183
+ return count;
25184
+ case "ObjectExpression":
25185
+ for (const prop of expr.properties) {
25186
+ if (prop.kind === "Property") {
25187
+ count += countExpressionNodes(prop.value);
25188
+ } else if (prop.kind === "SpreadElement") {
25189
+ count += countExpressionNodes(prop.argument);
25190
+ }
25191
+ }
25192
+ return count;
25193
+ case "ArrowFunction":
25194
+ if (expr.isExpression && expr.body && !Array.isArray(expr.body)) {
25195
+ count += countExpressionNodes(expr.body);
25196
+ } else if (Array.isArray(expr.body)) {
25197
+ for (const block of expr.body) {
25198
+ count += countBlockNodes(block);
25199
+ }
25200
+ }
25201
+ return count;
25202
+ case "FunctionExpression":
25203
+ if (expr.body) {
25204
+ for (const block of expr.body) {
25205
+ count += countBlockNodes(block);
25206
+ }
25207
+ }
25208
+ return count;
25209
+ case "AssignmentExpression":
25210
+ count += countExpressionNodes(expr.left);
25211
+ count += countExpressionNodes(expr.right);
25212
+ return count;
25213
+ case "UpdateExpression":
25214
+ count += countExpressionNodes(expr.argument);
25215
+ return count;
25216
+ case "SequenceExpression":
25217
+ for (const e of expr.expressions) {
25218
+ count += countExpressionNodes(e);
25219
+ }
25220
+ return count;
25221
+ case "AwaitExpression":
25222
+ count += countExpressionNodes(expr.argument);
25223
+ return count + 2;
25224
+ // Async adds complexity
25225
+ case "NewExpression":
25226
+ count += countExpressionNodes(expr.callee);
25227
+ for (const arg of expr.arguments) {
25228
+ count += countExpressionNodes(arg);
25229
+ }
25230
+ return count;
25231
+ case "TemplateLiteral":
25232
+ for (const e of expr.expressions) {
25233
+ count += countExpressionNodes(e);
25234
+ }
25235
+ return count;
25236
+ default:
25237
+ return count;
25238
+ }
25239
+ }
25240
+ function countBlockNodes(block) {
25241
+ let count = 1;
25242
+ for (const instr of block.instructions) {
25243
+ count += countInstructionNodes(instr);
25244
+ }
25245
+ return count;
25246
+ }
25247
+ function countInstructionNodes(instr) {
25248
+ switch (instr.kind) {
25249
+ case "Expression":
25250
+ return 1 + countExpressionNodes(instr.value);
25251
+ case "Assign":
25252
+ return 1 + countExpressionNodes(instr.value);
25253
+ case "Phi":
25254
+ return 1;
25255
+ default:
25256
+ return 1;
25257
+ }
25258
+ }
25259
+ function hasExternalCalls(expr) {
25260
+ if (!expr) return false;
25261
+ switch (expr.kind) {
25262
+ case "CallExpression": {
25263
+ if (expr.callee.kind === "Identifier") {
25264
+ const name = expr.callee.name;
25265
+ if (!["console", "Math", "JSON", "Object", "Array"].includes(name)) {
25266
+ return true;
25267
+ }
25268
+ }
25269
+ if (expr.callee.kind === "MemberExpression") {
25270
+ return true;
25271
+ }
25272
+ for (const arg of expr.arguments) {
25273
+ if (hasExternalCalls(arg)) return true;
25274
+ }
25275
+ return false;
25276
+ }
25277
+ case "ArrowFunction":
25278
+ if (expr.isExpression && expr.body && !Array.isArray(expr.body)) {
25279
+ return hasExternalCalls(expr.body);
25280
+ } else if (Array.isArray(expr.body)) {
25281
+ for (const block of expr.body) {
25282
+ if (blockHasExternalCalls(block)) return true;
25283
+ }
25284
+ }
25285
+ return false;
25286
+ case "FunctionExpression":
25287
+ if (expr.body) {
25288
+ for (const block of expr.body) {
25289
+ if (blockHasExternalCalls(block)) return true;
25290
+ }
25291
+ }
25292
+ return false;
25293
+ case "BinaryExpression":
25294
+ case "LogicalExpression":
25295
+ return hasExternalCalls(expr.left) || hasExternalCalls(expr.right);
25296
+ case "UnaryExpression":
25297
+ return hasExternalCalls(expr.argument);
25298
+ case "ConditionalExpression":
25299
+ return hasExternalCalls(expr.test) || hasExternalCalls(expr.consequent) || hasExternalCalls(expr.alternate);
25300
+ case "MemberExpression":
25301
+ return hasExternalCalls(expr.object);
25302
+ case "AssignmentExpression":
25303
+ return hasExternalCalls(expr.right);
25304
+ case "SequenceExpression":
25305
+ return expr.expressions.some((e) => hasExternalCalls(e));
25306
+ case "AwaitExpression":
25307
+ return true;
25308
+ // Await implies async external operation
25309
+ case "NewExpression":
25310
+ return true;
25311
+ // Constructor calls are external
25312
+ default:
25313
+ return false;
25314
+ }
25315
+ }
25316
+ function blockHasExternalCalls(block) {
25317
+ for (const instr of block.instructions) {
25318
+ if (instructionHasExternalCalls(instr)) return true;
25319
+ }
25320
+ return false;
25321
+ }
25322
+ function instructionHasExternalCalls(instr) {
25323
+ switch (instr.kind) {
25324
+ case "Expression":
25325
+ return hasExternalCalls(instr.value);
25326
+ case "Assign":
25327
+ return hasExternalCalls(instr.value);
25328
+ default:
25329
+ return false;
25330
+ }
25331
+ }
25332
+ function hasAsyncAwait(expr) {
25333
+ if (!expr) return false;
25334
+ switch (expr.kind) {
25335
+ case "AwaitExpression":
25336
+ return true;
25337
+ case "ArrowFunction":
25338
+ if (expr.isAsync) return true;
25339
+ if (expr.isExpression && expr.body && !Array.isArray(expr.body)) {
25340
+ return hasAsyncAwait(expr.body);
25341
+ } else if (Array.isArray(expr.body)) {
25342
+ for (const block of expr.body) {
25343
+ if (blockHasAsyncAwait(block)) return true;
25344
+ }
25345
+ }
25346
+ return false;
25347
+ case "FunctionExpression":
25348
+ if (expr.isAsync) return true;
25349
+ if (expr.body) {
25350
+ for (const block of expr.body) {
25351
+ if (blockHasAsyncAwait(block)) return true;
25352
+ }
25353
+ }
25354
+ return false;
25355
+ case "CallExpression":
25356
+ if (hasAsyncAwait(expr.callee)) return true;
25357
+ return expr.arguments.some((arg) => hasAsyncAwait(arg));
25358
+ case "BinaryExpression":
25359
+ case "LogicalExpression":
25360
+ return hasAsyncAwait(expr.left) || hasAsyncAwait(expr.right);
25361
+ case "ConditionalExpression":
25362
+ return hasAsyncAwait(expr.test) || hasAsyncAwait(expr.consequent) || hasAsyncAwait(expr.alternate);
25363
+ case "SequenceExpression":
25364
+ return expr.expressions.some((e) => hasAsyncAwait(e));
25365
+ default:
25366
+ return false;
25367
+ }
25368
+ }
25369
+ function blockHasAsyncAwait(block) {
25370
+ for (const instr of block.instructions) {
25371
+ if (instructionHasAsyncAwait(instr)) return true;
25372
+ }
25373
+ return false;
25374
+ }
25375
+ function instructionHasAsyncAwait(instr) {
25376
+ switch (instr.kind) {
25377
+ case "Expression":
25378
+ return hasAsyncAwait(instr.value);
25379
+ case "Assign":
25380
+ return hasAsyncAwait(instr.value);
25381
+ default:
25382
+ return false;
25383
+ }
25384
+ }
25385
+ function shouldAutoExtract(expr, ctx) {
25386
+ if (!expr) return false;
25387
+ if (!ctx.autoExtractEnabled) return false;
25388
+ const threshold = ctx.autoExtractThreshold ?? 3;
25389
+ if (expr.kind === "Identifier") {
25390
+ return true;
25391
+ }
25392
+ if (expr.kind === "ArrowFunction" || expr.kind === "FunctionExpression") {
25393
+ if (expr.kind === "ArrowFunction" && expr.isAsync || expr.kind === "FunctionExpression" && expr.isAsync || hasAsyncAwait(expr)) {
25394
+ return true;
25395
+ }
25396
+ if (hasExternalCalls(expr)) {
25397
+ return true;
25398
+ }
25399
+ const nodeCount2 = countExpressionNodes(expr);
25400
+ if (nodeCount2 >= threshold) {
25401
+ return true;
25402
+ }
25403
+ return false;
25404
+ }
25405
+ const nodeCount = countExpressionNodes(expr);
25406
+ return nodeCount >= threshold;
25407
+ }
25013
25408
  function extractHIRStaticHtml(jsx, ctx, parentPath = [], namespace = null) {
25014
25409
  if (jsx.isComponent || typeof jsx.tagName !== "string") {
25015
25410
  return {
25016
- html: "<!---->",
25411
+ html: "<!--fict:slot:start--><!--fict:slot:end-->",
25017
25412
  bindings: [
25018
25413
  {
25019
25414
  type: "child",
25020
25415
  path: [...parentPath],
25021
25416
  expr: jsx
25022
25417
  }
25023
- ]
25418
+ ],
25419
+ nodeCount: 1
25024
25420
  };
25025
25421
  }
25026
25422
  const tagName = jsx.tagName;
@@ -25031,7 +25427,11 @@ function extractHIRStaticHtml(jsx, ctx, parentPath = [], namespace = null) {
25031
25427
  if (attr.isSpread) {
25032
25428
  continue;
25033
25429
  }
25034
- const name = normalizeHIRAttrName(attr.name);
25430
+ let name = normalizeHIRAttrName(attr.name);
25431
+ const isResumableEvent = name.endsWith("$");
25432
+ if (isResumableEvent) {
25433
+ name = name.slice(0, -1);
25434
+ }
25035
25435
  if (name === "key") {
25036
25436
  if (attr.value && !isStaticValue(attr.value)) {
25037
25437
  bindings.push({
@@ -25066,12 +25466,14 @@ function extractHIRStaticHtml(jsx, ctx, parentPath = [], namespace = null) {
25066
25466
  changed = true;
25067
25467
  }
25068
25468
  }
25469
+ const shouldBeResumable = isResumableEvent && ctx.resumableEnabled || !isResumableEvent && ctx.resumableEnabled && shouldAutoExtract(attr.value ?? void 0, ctx);
25069
25470
  bindings.push({
25070
25471
  type: "event",
25071
25472
  path: [...parentPath],
25072
25473
  name: eventName.toLowerCase(),
25073
25474
  expr: attr.value ?? void 0,
25074
- eventOptions: { capture, passive, once }
25475
+ eventOptions: { capture, passive, once },
25476
+ resumable: shouldBeResumable
25075
25477
  });
25076
25478
  continue;
25077
25479
  }
@@ -25127,7 +25529,7 @@ function extractHIRStaticHtml(jsx, ctx, parentPath = [], namespace = null) {
25127
25529
  const childResult = extractHIRStaticHtml(child.value, ctx, childPath, resolvedNamespace);
25128
25530
  html += childResult.html;
25129
25531
  bindings.push(...childResult.bindings);
25130
- childIndex++;
25532
+ childIndex += childResult.nodeCount;
25131
25533
  } else if (child.kind === "expression") {
25132
25534
  const inline = hasAdjacentInline(i);
25133
25535
  if (!inline && isLikelyTextExpression(child.value, ctx)) {
@@ -25140,7 +25542,7 @@ function extractHIRStaticHtml(jsx, ctx, parentPath = [], namespace = null) {
25140
25542
  namespace: resolvedNamespace
25141
25543
  });
25142
25544
  } else {
25143
- html += "<!---->";
25545
+ html += "<!--fict:slot:start--><!--fict:slot:end-->";
25144
25546
  bindings.push({
25145
25547
  type: "child",
25146
25548
  path: [...parentPath, childIndex],
@@ -25148,6 +25550,8 @@ function extractHIRStaticHtml(jsx, ctx, parentPath = [], namespace = null) {
25148
25550
  // Track namespace for dynamic child bindings
25149
25551
  namespace: resolvedNamespace
25150
25552
  });
25553
+ childIndex++;
25554
+ continue;
25151
25555
  }
25152
25556
  childIndex++;
25153
25557
  }
@@ -25158,6 +25562,7 @@ function extractHIRStaticHtml(jsx, ctx, parentPath = [], namespace = null) {
25158
25562
  return {
25159
25563
  html,
25160
25564
  bindings,
25565
+ nodeCount: 1,
25161
25566
  isSVG: needsSVG || void 0,
25162
25567
  isMathML: needsMathML || void 0
25163
25568
  };
@@ -25249,6 +25654,17 @@ function lowerIntrinsicElement(jsx, ctx) {
25249
25654
  const eventName = binding.name;
25250
25655
  const hasEventOptions = binding.eventOptions && (binding.eventOptions.capture || binding.eventOptions.passive || binding.eventOptions.once);
25251
25656
  const isDelegated = DelegatedEvents.has(eventName) && !hasEventOptions;
25657
+ if (binding.resumable && !hasEventOptions) {
25658
+ emitResumableEventBinding(
25659
+ targetId,
25660
+ eventName,
25661
+ binding.expr,
25662
+ statements,
25663
+ ctx,
25664
+ containingRegion
25665
+ );
25666
+ continue;
25667
+ }
25252
25668
  const hirDataBinding = isDelegated && binding.expr ? extractDelegatedEventDataFromHIR(binding.expr, ctx) : null;
25253
25669
  if (hirDataBinding) {
25254
25670
  ctx.delegatedEventsUsed?.add(eventName);
@@ -25545,13 +25961,16 @@ function resolveHIRBindingPath(path2, cache, statements, ctx) {
25545
25961
  ancestorId = cache.get("");
25546
25962
  relativePath = path2;
25547
25963
  }
25548
- let currentExpr = ancestorId;
25549
- for (const index of relativePath) {
25550
- currentExpr = t4.memberExpression(currentExpr, t4.identifier("firstChild"));
25551
- for (let i = 0; i < index; i++) {
25552
- currentExpr = t4.memberExpression(currentExpr, t4.identifier("nextSibling"));
25553
- }
25964
+ if (relativePath.length === 0) {
25965
+ cache.set(key, ancestorId);
25966
+ return ancestorId;
25554
25967
  }
25968
+ ctx.helpersUsed.add("resolvePath");
25969
+ const pathExpr = t4.arrayExpression(relativePath.map((index) => t4.numericLiteral(index)));
25970
+ const currentExpr = t4.callExpression(t4.identifier(RUNTIME_ALIASES.resolvePath), [
25971
+ ancestorId,
25972
+ pathExpr
25973
+ ]);
25555
25974
  const varId = genTemp(ctx, "el");
25556
25975
  statements.push(t4.variableDeclaration("const", [t4.variableDeclarator(varId, currentExpr)]));
25557
25976
  cache.set(key, varId);
@@ -25559,7 +25978,16 @@ function resolveHIRBindingPath(path2, cache, statements, ctx) {
25559
25978
  }
25560
25979
  function emitHIRChildBinding(markerId, expr, statements, ctx, containingRegion, namespace) {
25561
25980
  const { t: t4 } = ctx;
25562
- const parentId = t4.memberExpression(markerId, t4.identifier("parentNode"));
25981
+ ctx.helpersUsed.add("getSlotEnd");
25982
+ const endMarkerId = genTemp(ctx, "end");
25983
+ statements.push(
25984
+ t4.variableDeclaration("const", [
25985
+ t4.variableDeclarator(
25986
+ endMarkerId,
25987
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.getSlotEnd), [markerId])
25988
+ )
25989
+ ])
25990
+ );
25563
25991
  if (namespace !== void 0) {
25564
25992
  ctx.namespaceContext = namespace;
25565
25993
  }
@@ -25578,26 +26006,26 @@ function emitHIRChildBinding(markerId, expr, statements, ctx, containingRegion,
25578
26006
  return;
25579
26007
  }
25580
26008
  if (expr.kind === "ConditionalExpression" || expr.kind === "LogicalExpression" && expr.operator === "&&") {
25581
- emitConditionalChild(parentId, markerId, expr, statements, ctx);
26009
+ emitConditionalChild(markerId, endMarkerId, expr, statements, ctx);
25582
26010
  return;
25583
26011
  }
25584
26012
  if (expr.kind === "CallExpression" || expr.kind === "OptionalCallExpression") {
25585
26013
  const callee = expr.callee;
25586
26014
  if ((callee.kind === "MemberExpression" || callee.kind === "OptionalMemberExpression") && callee.property.kind === "Identifier" && callee.property.name === "map") {
25587
- emitListChild(parentId, markerId, expr, statements, ctx);
26015
+ emitListChild(markerId, endMarkerId, expr, statements, ctx);
25588
26016
  return;
25589
26017
  }
25590
26018
  }
25591
26019
  if (expr.kind === "JSXElement") {
25592
26020
  const childExpr = lowerJSXElement(expr, ctx);
25593
- ctx.helpersUsed.add("insert");
26021
+ ctx.helpersUsed.add("insertBetween");
25594
26022
  ctx.helpersUsed.add("createElement");
25595
26023
  statements.push(
25596
26024
  t4.expressionStatement(
25597
- t4.callExpression(t4.identifier(RUNTIME_ALIASES.insert), [
25598
- parentId,
25599
- t4.arrowFunctionExpression([], childExpr),
26025
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.insertBetween), [
25600
26026
  markerId,
26027
+ endMarkerId,
26028
+ t4.arrowFunctionExpression([], childExpr),
25601
26029
  t4.identifier(RUNTIME_ALIASES.createElement)
25602
26030
  ])
25603
26031
  )
@@ -25605,20 +26033,280 @@ function emitHIRChildBinding(markerId, expr, statements, ctx, containingRegion,
25605
26033
  return;
25606
26034
  }
25607
26035
  const valueExpr = lowerDomExpression(expr, ctx, containingRegion);
25608
- ctx.helpersUsed.add("insert");
26036
+ ctx.helpersUsed.add("insertBetween");
25609
26037
  ctx.helpersUsed.add("createElement");
25610
26038
  statements.push(
25611
26039
  t4.expressionStatement(
25612
- t4.callExpression(t4.identifier(RUNTIME_ALIASES.insert), [
25613
- parentId,
25614
- t4.arrowFunctionExpression([], valueExpr),
26040
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.insertBetween), [
25615
26041
  markerId,
26042
+ endMarkerId,
26043
+ t4.arrowFunctionExpression([], valueExpr),
25616
26044
  t4.identifier(RUNTIME_ALIASES.createElement)
25617
26045
  ])
25618
26046
  )
25619
26047
  );
25620
26048
  }
25621
- function emitConditionalChild(parentId, markerId, expr, statements, ctx) {
26049
+ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, containingRegion) {
26050
+ const { t: t4 } = ctx;
26051
+ if (!ctx.resumableEnabled) {
26052
+ return;
26053
+ }
26054
+ const prevWrapTracked = ctx.wrapTrackedExpressions;
26055
+ ctx.wrapTrackedExpressions = false;
26056
+ const valueExpr = lowerDomExpression(expr, ctx, containingRegion, {
26057
+ skipHookAccessors: true,
26058
+ skipRegionRootOverride: true
26059
+ });
26060
+ ctx.wrapTrackedExpressions = prevWrapTracked;
26061
+ const eventParam = t4.identifier("event");
26062
+ const elParam = t4.identifier("el");
26063
+ const scopeParam = t4.identifier("scopeId");
26064
+ const ensureHandlerParam = (fn) => {
26065
+ if (t4.isArrowFunctionExpression(fn)) {
26066
+ if (fn.params.length > 0) return fn;
26067
+ return t4.arrowFunctionExpression([eventParam], fn.body, fn.async);
26068
+ }
26069
+ if (t4.isFunctionExpression(fn)) {
26070
+ if (fn.params.length > 0) return fn;
26071
+ return t4.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
26072
+ }
26073
+ if (t4.isIdentifier(fn) || t4.isMemberExpression(fn)) {
26074
+ return fn;
26075
+ }
26076
+ if (t4.isCallExpression(fn) && fn.arguments.length === 0 && (t4.isIdentifier(fn.callee) || t4.isMemberExpression(fn.callee))) {
26077
+ return fn.callee;
26078
+ }
26079
+ return t4.functionExpression(
26080
+ null,
26081
+ [eventParam],
26082
+ t4.blockStatement([
26083
+ t4.returnStatement(
26084
+ t4.callExpression(
26085
+ t4.memberExpression(fn, t4.identifier("call")),
26086
+ [t4.thisExpression(), eventParam]
26087
+ )
26088
+ )
26089
+ ])
26090
+ );
26091
+ };
26092
+ const handlerExpr = ensureHandlerParam(valueExpr);
26093
+ const handlerId = t4.identifier(`__fict_e${ctx.resumableHandlerCounter ?? 0}`);
26094
+ ctx.resumableHandlerCounter = (ctx.resumableHandlerCounter ?? 0) + 1;
26095
+ const captured = /* @__PURE__ */ new Set();
26096
+ collectExpressionIdentifiersDeep(expr, captured);
26097
+ const lexicalNames = Array.from(captured).filter((name) => ctx.signalVars?.has(name));
26098
+ const propsName = ctx.propsParamName && captured.has(ctx.propsParamName) ? ctx.propsParamName : null;
26099
+ const functionDeps = [];
26100
+ const functionDepRenames = /* @__PURE__ */ new Map();
26101
+ for (const name of captured) {
26102
+ if (ctx.functionVars?.has(name) && !ctx.signalVars?.has(name)) {
26103
+ const hirDef = ctx.componentFunctionDefs?.get(name);
26104
+ if (hirDef) {
26105
+ functionDeps.push(name);
26106
+ let hoistedName = ctx.hoistedFunctionDepNames?.get(name);
26107
+ if (!hoistedName) {
26108
+ hoistedName = `__fict_fn_${name}_${ctx.hoistedFunctionDepCounter ?? 0}`;
26109
+ ctx.hoistedFunctionDepCounter = (ctx.hoistedFunctionDepCounter ?? 0) + 1;
26110
+ ctx.hoistedFunctionDepNames?.set(name, hoistedName);
26111
+ const loweredFn = lowerDomExpression(hirDef, ctx, null, {
26112
+ skipHookAccessors: true,
26113
+ skipRegionRootOverride: true
26114
+ });
26115
+ const hoistedDecl = t4.variableDeclaration("const", [
26116
+ t4.variableDeclarator(t4.identifier(hoistedName), loweredFn)
26117
+ ]);
26118
+ const hoistedExport = t4.exportNamedDeclaration(hoistedDecl, []);
26119
+ ctx.hoistedResumableStatements?.push(hoistedExport);
26120
+ }
26121
+ functionDepRenames.set(name, hoistedName);
26122
+ }
26123
+ }
26124
+ }
26125
+ let finalHandlerExpr = handlerExpr;
26126
+ if (functionDepRenames.size > 0) {
26127
+ finalHandlerExpr = renameIdentifiersInExpr(handlerExpr, functionDepRenames, t4);
26128
+ }
26129
+ const bodyStatements = [];
26130
+ if (lexicalNames.length > 0) {
26131
+ ctx.helpersUsed.add("useLexicalScope");
26132
+ bodyStatements.push(
26133
+ t4.variableDeclaration("const", [
26134
+ t4.variableDeclarator(
26135
+ t4.arrayPattern(lexicalNames.map((name) => t4.identifier(name))),
26136
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.useLexicalScope), [
26137
+ scopeParam,
26138
+ t4.arrayExpression(lexicalNames.map((name) => t4.stringLiteral(name)))
26139
+ ])
26140
+ )
26141
+ ])
26142
+ );
26143
+ }
26144
+ if (propsName) {
26145
+ ctx.helpersUsed.add("getScopeProps");
26146
+ bodyStatements.push(
26147
+ t4.variableDeclaration("const", [
26148
+ t4.variableDeclarator(
26149
+ t4.identifier(propsName),
26150
+ t4.logicalExpression(
26151
+ "||",
26152
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.getScopeProps), [scopeParam]),
26153
+ t4.objectExpression([])
26154
+ )
26155
+ )
26156
+ ])
26157
+ );
26158
+ }
26159
+ const handlerVar = t4.identifier("__handler");
26160
+ bodyStatements.push(
26161
+ t4.variableDeclaration("const", [t4.variableDeclarator(handlerVar, finalHandlerExpr)])
26162
+ );
26163
+ bodyStatements.push(
26164
+ t4.returnStatement(
26165
+ t4.callExpression(t4.memberExpression(handlerVar, t4.identifier("call")), [elParam, eventParam])
26166
+ )
26167
+ );
26168
+ const exportedHandler = t4.exportNamedDeclaration(
26169
+ t4.variableDeclaration("const", [
26170
+ t4.variableDeclarator(
26171
+ handlerId,
26172
+ t4.arrowFunctionExpression(
26173
+ [scopeParam, eventParam, elParam],
26174
+ t4.blockStatement(bodyStatements)
26175
+ )
26176
+ )
26177
+ ]),
26178
+ []
26179
+ );
26180
+ ctx.hoistedResumableStatements?.push(exportedHandler);
26181
+ ctx.helpersUsed.add("qrl");
26182
+ const qrlExpr = t4.callExpression(t4.identifier(RUNTIME_ALIASES.qrl), [
26183
+ genModuleUrlExpr(ctx),
26184
+ t4.stringLiteral(handlerId.name)
26185
+ ]);
26186
+ statements.push(
26187
+ t4.expressionStatement(
26188
+ t4.callExpression(t4.memberExpression(targetId, t4.identifier("setAttribute")), [
26189
+ t4.stringLiteral(`on:${eventName}`),
26190
+ qrlExpr
26191
+ ])
26192
+ )
26193
+ );
26194
+ }
26195
+ function registerResumableComponent(componentName, ctx) {
26196
+ if (!ctx.resumableEnabled) return;
26197
+ if (!ctx.hoistedResumableStatements || !ctx.resumableComponents) return;
26198
+ if (ctx.resumableComponents.has(componentName)) return;
26199
+ const { t: t4 } = ctx;
26200
+ const resumeExport = `__fict_r${ctx.resumableComponentCounter ?? 0}`;
26201
+ ctx.resumableComponentCounter = (ctx.resumableComponentCounter ?? 0) + 1;
26202
+ const scopeParam = t4.identifier("scopeId");
26203
+ const hostParam = t4.identifier("host");
26204
+ const snapshotId = t4.identifier("snapshot");
26205
+ const ctxId = t4.identifier("ctx");
26206
+ ctx.helpersUsed.add("getSSRScope");
26207
+ ctx.helpersUsed.add("ensureScope");
26208
+ ctx.helpersUsed.add("prepareContext");
26209
+ ctx.helpersUsed.add("pushContext");
26210
+ ctx.helpersUsed.add("popContext");
26211
+ ctx.helpersUsed.add("hydrateComponent");
26212
+ ctx.helpersUsed.add("qrl");
26213
+ const snapshotDecl = t4.variableDeclaration("const", [
26214
+ t4.variableDeclarator(
26215
+ snapshotId,
26216
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.getSSRScope), [scopeParam])
26217
+ )
26218
+ ]);
26219
+ const earlyReturn = t4.ifStatement(t4.unaryExpression("!", snapshotId), t4.returnStatement());
26220
+ const ensureCtxDecl = t4.variableDeclaration("const", [
26221
+ t4.variableDeclarator(
26222
+ ctxId,
26223
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.ensureScope), [
26224
+ scopeParam,
26225
+ hostParam,
26226
+ snapshotId
26227
+ ])
26228
+ )
26229
+ ]);
26230
+ const prepareCtx = t4.expressionStatement(
26231
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.prepareContext), [ctxId])
26232
+ );
26233
+ const pushCtx = t4.expressionStatement(
26234
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.pushContext), [])
26235
+ );
26236
+ const hydrateCall = t4.expressionStatement(
26237
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.hydrateComponent), [
26238
+ t4.arrowFunctionExpression(
26239
+ [],
26240
+ t4.callExpression(t4.identifier(componentName), [
26241
+ t4.logicalExpression(
26242
+ "||",
26243
+ t4.memberExpression(snapshotId, t4.identifier("props")),
26244
+ t4.objectExpression([])
26245
+ )
26246
+ ])
26247
+ ),
26248
+ hostParam
26249
+ ])
26250
+ );
26251
+ const popCtx = t4.expressionStatement(
26252
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.popContext), [])
26253
+ );
26254
+ const resumeFnId = t4.identifier(resumeExport);
26255
+ const resumeFn = t4.exportNamedDeclaration(
26256
+ t4.variableDeclaration("const", [
26257
+ t4.variableDeclarator(
26258
+ resumeFnId,
26259
+ t4.arrowFunctionExpression(
26260
+ [scopeParam, hostParam],
26261
+ t4.blockStatement([
26262
+ snapshotDecl,
26263
+ earlyReturn,
26264
+ ensureCtxDecl,
26265
+ t4.tryStatement(
26266
+ t4.blockStatement([prepareCtx, pushCtx, hydrateCall]),
26267
+ null,
26268
+ t4.blockStatement([popCtx])
26269
+ )
26270
+ ])
26271
+ )
26272
+ )
26273
+ ]),
26274
+ []
26275
+ );
26276
+ ctx.helpersUsed.add("registerResume");
26277
+ const registerCall = t4.expressionStatement(
26278
+ t4.callExpression(t4.identifier(RUNTIME_ALIASES.registerResume), [
26279
+ t4.stringLiteral(resumeExport),
26280
+ resumeFnId
26281
+ ])
26282
+ );
26283
+ const metaId = t4.identifier(`__fict_meta_${componentName}`);
26284
+ const moduleUrlExpr = genModuleUrlExpr(ctx);
26285
+ const typeKeyExpr = t4.binaryExpression("+", t4.stringLiteral(`${componentName}@`), moduleUrlExpr);
26286
+ const resumeQrlExpr = t4.callExpression(t4.identifier(RUNTIME_ALIASES.qrl), [
26287
+ genModuleUrlExpr(ctx),
26288
+ t4.stringLiteral(resumeExport)
26289
+ ]);
26290
+ const metaDecl = t4.variableDeclaration("const", [
26291
+ t4.variableDeclarator(
26292
+ metaId,
26293
+ t4.objectExpression([
26294
+ t4.objectProperty(t4.identifier("id"), typeKeyExpr),
26295
+ t4.objectProperty(t4.identifier("resume"), resumeQrlExpr)
26296
+ ])
26297
+ )
26298
+ ]);
26299
+ const assignMeta = t4.expressionStatement(
26300
+ t4.assignmentExpression(
26301
+ "=",
26302
+ t4.memberExpression(t4.identifier(componentName), t4.identifier("__fictMeta")),
26303
+ metaId
26304
+ )
26305
+ );
26306
+ ctx.hoistedResumableStatements.push(resumeFn, registerCall, metaDecl, assignMeta);
26307
+ ctx.resumableComponents.set(componentName, { resumeExport, typeKey: componentName });
26308
+ }
26309
+ function emitConditionalChild(startMarkerId, endMarkerId, expr, statements, ctx) {
25622
26310
  const { t: t4 } = ctx;
25623
26311
  ctx.helpersUsed.add("conditional");
25624
26312
  ctx.helpersUsed.add("createElement");
@@ -25659,7 +26347,10 @@ function emitConditionalChild(parentId, markerId, expr, statements, ctx) {
25659
26347
  ];
25660
26348
  if (alternate) {
25661
26349
  args.push(t4.arrowFunctionExpression([], alternate));
26350
+ } else {
26351
+ args.push(t4.identifier("undefined"));
25662
26352
  }
26353
+ args.push(startMarkerId, endMarkerId);
25663
26354
  statements.push(
25664
26355
  t4.variableDeclaration("const", [
25665
26356
  t4.variableDeclarator(
@@ -25668,14 +26359,6 @@ function emitConditionalChild(parentId, markerId, expr, statements, ctx) {
25668
26359
  )
25669
26360
  ])
25670
26361
  );
25671
- statements.push(
25672
- t4.expressionStatement(
25673
- t4.callExpression(t4.memberExpression(parentId, t4.identifier("insertBefore")), [
25674
- t4.memberExpression(bindingId, t4.identifier("marker")),
25675
- markerId
25676
- ])
25677
- )
25678
- );
25679
26362
  statements.push(
25680
26363
  t4.expressionStatement(
25681
26364
  t4.optionalCallExpression(
@@ -26140,6 +26823,8 @@ function buildListCallExpression(expr, statements, ctx) {
26140
26823
  }
26141
26824
  const keyExpr = extractKeyFromMapCallback(mapCallback);
26142
26825
  const isKeyed = !!keyExpr;
26826
+ const hasRestParam = (mapCallback.kind === "ArrowFunction" || mapCallback.kind === "FunctionExpression") && Array.isArray(mapCallback.rawParams) && mapCallback.rawParams.some((param) => t4.isRestElement(param));
26827
+ const canConstifyKey = isKeyed && keyExpr && !hasRestParam;
26143
26828
  if (isKeyed) {
26144
26829
  ctx.helpersUsed.add("keyedList");
26145
26830
  } else {
@@ -26153,7 +26838,7 @@ function buildListCallExpression(expr, statements, ctx) {
26153
26838
  const prevListKeyExpr = ctx.listKeyExpr;
26154
26839
  const prevListItemParamName = ctx.listItemParamName;
26155
26840
  const prevListKeyParamName = ctx.listKeyParamName;
26156
- if (isKeyed && keyExpr) {
26841
+ if (canConstifyKey && keyExpr) {
26157
26842
  ctx.listKeyExpr = keyExpr;
26158
26843
  ctx.listKeyParamName = "__key";
26159
26844
  if (mapCallback.kind === "ArrowFunction" || mapCallback.kind === "FunctionExpression") {
@@ -26239,7 +26924,7 @@ function buildListCallExpression(expr, statements, ctx) {
26239
26924
  keyExprAst
26240
26925
  );
26241
26926
  const hasIndexParam = (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) && callbackExpr.params.length >= 2;
26242
- if (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) {
26927
+ if (canConstifyKey && (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr))) {
26243
26928
  const newParams = [...callbackExpr.params];
26244
26929
  while (newParams.length < 2) {
26245
26930
  newParams.push(t4.identifier(newParams.length === 0 ? "__item" : "__index"));
@@ -26282,40 +26967,16 @@ function buildListCallExpression(expr, statements, ctx) {
26282
26967
  }
26283
26968
  return listCall;
26284
26969
  }
26285
- function emitListChild(parentId, markerId, expr, statements, ctx) {
26970
+ function emitListChild(startMarkerId, endMarkerId, expr, statements, ctx) {
26286
26971
  const { t: t4 } = ctx;
26287
26972
  const listCall = buildListCallExpression(expr, statements, ctx);
26288
26973
  if (!listCall) return;
26974
+ if (t4.isCallExpression(listCall)) {
26975
+ listCall.arguments.push(startMarkerId, endMarkerId);
26976
+ }
26289
26977
  ctx.helpersUsed.add("onDestroy");
26290
- ctx.helpersUsed.add("toNodeArray");
26291
26978
  const listId = genTemp(ctx, "list");
26292
26979
  statements.push(t4.variableDeclaration("const", [t4.variableDeclarator(listId, listCall)]));
26293
- const markersId = genTemp(ctx, "markers");
26294
- statements.push(
26295
- t4.variableDeclaration("const", [
26296
- t4.variableDeclarator(
26297
- markersId,
26298
- t4.callExpression(t4.identifier(RUNTIME_ALIASES.toNodeArray), [
26299
- t4.memberExpression(listId, t4.identifier("marker"))
26300
- ])
26301
- )
26302
- ])
26303
- );
26304
- const mId = genTemp(ctx, "m");
26305
- statements.push(
26306
- t4.forOfStatement(
26307
- t4.variableDeclaration("const", [t4.variableDeclarator(mId)]),
26308
- markersId,
26309
- t4.blockStatement([
26310
- t4.expressionStatement(
26311
- t4.callExpression(t4.memberExpression(parentId, t4.identifier("insertBefore")), [
26312
- mId,
26313
- markerId
26314
- ])
26315
- )
26316
- ])
26317
- )
26318
- );
26319
26980
  statements.push(
26320
26981
  t4.expressionStatement(
26321
26982
  t4.optionalCallExpression(
@@ -26352,6 +27013,9 @@ function lowerHIRWithRegions(program, t4, options, macroAliases) {
26352
27013
  program.functions.filter((fn) => !!fn.name).map((fn) => [fn.name, fn])
26353
27014
  );
26354
27015
  ctx.options = options;
27016
+ ctx.resumableEnabled = options?.resumable === true;
27017
+ ctx.autoExtractEnabled = options?.autoExtractHandlers ?? options?.resumable === true;
27018
+ ctx.autoExtractThreshold = options?.autoExtractThreshold ?? 3;
26355
27019
  const body = [];
26356
27020
  const topLevelAliases = /* @__PURE__ */ new Set();
26357
27021
  let topLevelCtxInjected = false;
@@ -26598,6 +27262,9 @@ function lowerHIRWithRegions(program, t4, options, macroAliases) {
26598
27262
  lowerableBuffer.push(stmt);
26599
27263
  }
26600
27264
  flushLowerableBuffer();
27265
+ if (ctx.resumableEnabled && ctx.hoistedResumableStatements && ctx.hoistedResumableStatements.length > 0) {
27266
+ body.push(...ctx.hoistedResumableStatements);
27267
+ }
26601
27268
  for (const func of generatedFunctions.values()) {
26602
27269
  body.push(func.stmt);
26603
27270
  if (func.stmt.id?.name) emittedFunctionNames.add(func.stmt.id.name);
@@ -26638,12 +27305,15 @@ function lowerTopLevelStatementBlock(statements, ctx, t4, name = "__module_segme
26638
27305
  ctx.storeVars = storeVars;
26639
27306
  ctx.memoVars = memoVars;
26640
27307
  ctx.mutatedVars = mutatedVars;
27308
+ const componentFunctionDefs = ctx.componentFunctionDefs ?? /* @__PURE__ */ new Map();
27309
+ ctx.componentFunctionDefs = componentFunctionDefs;
26641
27310
  for (const block of fn.blocks) {
26642
27311
  for (const instr of block.instructions) {
26643
27312
  if (instr.kind === "Assign") {
26644
27313
  const target = deSSAVarName(instr.target.name);
26645
27314
  if (instr.value.kind === "ArrowFunction" || instr.value.kind === "FunctionExpression") {
26646
27315
  functionVars.add(target);
27316
+ componentFunctionDefs.set(target, instr.value);
26647
27317
  }
26648
27318
  if (instr.value.kind === "CallExpression" || instr.value.kind === "OptionalCallExpression") {
26649
27319
  const callKind = getReactiveCallKind(instr.value, ctx);
@@ -26811,6 +27481,8 @@ function lowerFunctionWithRegions(fn, ctx, options) {
26811
27481
  ctx.mutatedVars = /* @__PURE__ */ new Set();
26812
27482
  ctx.noMemo = !!(prevNoMemo || fn.meta?.noMemo);
26813
27483
  ctx.hookResultVarMap = /* @__PURE__ */ new Map();
27484
+ const prevComponentFunctionDefs = ctx.componentFunctionDefs;
27485
+ ctx.componentFunctionDefs = /* @__PURE__ */ new Map();
26814
27486
  const hookResultVars = /* @__PURE__ */ new Set();
26815
27487
  const hookAccessorAliases = /* @__PURE__ */ new Set();
26816
27488
  const prevPropsParam = ctx.propsParamName;
@@ -26827,6 +27499,7 @@ function lowerFunctionWithRegions(fn, ctx, options) {
26827
27499
  const target = deSSAVarName(instr.target.name);
26828
27500
  if (instr.value.kind === "ArrowFunction" || instr.value.kind === "FunctionExpression") {
26829
27501
  ctx.functionVars?.add(target);
27502
+ ctx.componentFunctionDefs?.set(target, instr.value);
26830
27503
  }
26831
27504
  if (instr.value.kind === "CallExpression" || instr.value.kind === "OptionalCallExpression") {
26832
27505
  const callKind = getReactiveCallKind(instr.value, ctx);
@@ -27122,6 +27795,7 @@ function lowerFunctionWithRegions(fn, ctx, options) {
27122
27795
  ctx.externalTracked = prevExternalTracked;
27123
27796
  ctx.signalVars = prevSignalVars;
27124
27797
  ctx.functionVars = prevFunctionVars;
27798
+ ctx.componentFunctionDefs = prevComponentFunctionDefs;
27125
27799
  ctx.memoVars = prevMemoVars;
27126
27800
  ctx.storeVars = prevStoreVars;
27127
27801
  ctx.mutatedVars = prevMutatedVars;
@@ -27139,6 +27813,7 @@ function lowerFunctionWithRegions(fn, ctx, options) {
27139
27813
  ctx.externalTracked = prevExternalTracked;
27140
27814
  ctx.signalVars = prevSignalVars;
27141
27815
  ctx.functionVars = prevFunctionVars;
27816
+ ctx.componentFunctionDefs = prevComponentFunctionDefs;
27142
27817
  ctx.memoVars = prevMemoVars;
27143
27818
  ctx.storeVars = prevStoreVars;
27144
27819
  ctx.mutatedVars = prevMutatedVars;
@@ -27235,6 +27910,9 @@ function lowerFunctionWithRegions(fn, ctx, options) {
27235
27910
  fn.loc
27236
27911
  );
27237
27912
  funcDecl.async = isAsync;
27913
+ if (isComponent && fn.name) {
27914
+ registerResumableComponent(fn.name, ctx);
27915
+ }
27238
27916
  ctx.needsCtx = prevNeedsCtx;
27239
27917
  ctx.shadowedNames = prevShadowed;
27240
27918
  ctx.localDeclaredNames = prevLocalDeclared;
@@ -27242,6 +27920,7 @@ function lowerFunctionWithRegions(fn, ctx, options) {
27242
27920
  ctx.externalTracked = prevExternalTracked;
27243
27921
  ctx.signalVars = prevSignalVars;
27244
27922
  ctx.functionVars = prevFunctionVars;
27923
+ ctx.componentFunctionDefs = prevComponentFunctionDefs;
27245
27924
  ctx.memoVars = prevMemoVars;
27246
27925
  ctx.storeVars = prevStoreVars;
27247
27926
  ctx.mutatedVars = prevMutatedVars;