octane 0.3.0 → 0.3.2

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.
Files changed (55) hide show
  1. package/dist/cjs/constants.cjs +18 -25
  2. package/dist/cjs/css.cjs +6 -0
  3. package/dist/cjs/dom-binding-protocol.cjs +37 -14
  4. package/dist/cjs/hydration/control-capture.cjs +12 -4
  5. package/dist/cjs/hydration/event-capture.cjs +6 -7
  6. package/dist/cjs/hydration-markers.cjs +40 -2
  7. package/dist/cjs/index.cjs +2 -0
  8. package/dist/cjs/runtime-tags.cjs +55 -0
  9. package/dist/cjs/runtime.cjs +235 -148
  10. package/dist/cjs/runtime.server.cjs +110 -80
  11. package/dist/cjs/server/streamed-signals.cjs +102 -64
  12. package/dist/cjs/signals/control-binding.cjs +2 -1
  13. package/dist/cjs/stream-protocol.cjs +9 -8
  14. package/dist/cjs/version.cjs +1 -1
  15. package/dist/compiler/compile.js +550 -35
  16. package/dist/compiler/dom-bindings.js +5 -0
  17. package/dist/compiler/hydrate-boundaries.js +118 -0
  18. package/dist/compiler/private-context.js +160 -0
  19. package/dist/constants.d.ts +7 -18
  20. package/dist/constants.js +11 -9
  21. package/dist/css.d.ts +7 -0
  22. package/dist/css.js +4 -0
  23. package/dist/dom-binding-program.js +12 -5
  24. package/dist/dom-binding-protocol.d.ts +14 -1
  25. package/dist/dom-binding-protocol.js +40 -14
  26. package/dist/hydration/control-capture.d.ts +2 -0
  27. package/dist/hydration/control-capture.js +18 -5
  28. package/dist/hydration/event-capture.js +1 -2
  29. package/dist/hydration/independent-island.js +5 -5
  30. package/dist/hydration/stream-delivery.d.ts +1 -1
  31. package/dist/hydration/stream-delivery.js +16 -9
  32. package/dist/hydration/stream-result-receiver.d.ts +1 -0
  33. package/dist/hydration/stream-result-receiver.js +8 -4
  34. package/dist/hydration-markers.d.ts +30 -0
  35. package/dist/hydration-markers.js +27 -1
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.js +2 -0
  38. package/dist/react/index.js +1 -1
  39. package/dist/react/react-compat-shared.js +5 -3
  40. package/dist/react/shared.d.ts +1 -3
  41. package/dist/react/shared.js +1 -1
  42. package/dist/runtime-tags.d.ts +34 -0
  43. package/dist/runtime-tags.js +22 -0
  44. package/dist/runtime.d.ts +9 -14
  45. package/dist/runtime.js +213 -106
  46. package/dist/runtime.server.d.ts +10 -5
  47. package/dist/runtime.server.js +101 -56
  48. package/dist/server/streamed-signals.d.ts +1 -0
  49. package/dist/server/streamed-signals.js +102 -64
  50. package/dist/signals/control-binding.js +4 -2
  51. package/dist/stream-protocol.js +20 -9
  52. package/dist/universal-core.js +8 -4
  53. package/dist/universal-native.js +1 -1
  54. package/dist/version.js +1 -1
  55. package/package.json +3 -3
@@ -56,6 +56,7 @@ import {
56
56
  analyzeCallbackDependencies,
57
57
  analyzeHookDependencies,
58
58
  applyHookDependencies,
59
+ collectReassignedBindings,
59
60
  isInvariantLiteral,
60
61
  } from './hook-deps.js';
61
62
  import {
@@ -83,6 +84,8 @@ import {
83
84
  prepareServerRendererBoundaryRegions,
84
85
  } from './compile-renderer-boundaries.js';
85
86
  import {
87
+ compiledSplitHydrateTagsForAst,
88
+ privateCompiledContextsForHydrateAst,
86
89
  hydrateBoundaryPathFromId,
87
90
  prepareHydrateBoundaries,
88
91
  prepareServerHydrateBoundaries,
@@ -125,6 +128,7 @@ import { assertNoLegacyContextProviders } from './context-provider.js';
125
128
  import { applyCssModuleConstants } from './css-module-constants.js';
126
129
  import { assertUniversalRuntimeTarget, normalizeUniversalRuntime } from './universal-runtime.js';
127
130
  import { findLocalVoidRootCallees } from './local-void-roots.js';
131
+ import { findPrivateCompiledContexts } from './private-context.js';
128
132
 
129
133
  // DOM truth tables shared with the client/server runtimes (via constants.ts) —
130
134
  // static bakes and dynamic writes MUST agree on which attributes render, under
@@ -535,12 +539,17 @@ function attrBindingUpdateHelper(bind, inlineBindingGuards = false) {
535
539
  }
536
540
  }
537
541
 
538
- function canCarryDirectSignalHandle(node, conservativeResult = false) {
542
+ function canCarryDirectSignalHandle(
543
+ node,
544
+ conservativeResult = false,
545
+ retainLocalCapability = false,
546
+ ) {
539
547
  if (
540
548
  !node ||
541
549
  node.metadata?.octane_string_child ||
542
550
  node.metadata?.octane_primitive_text_child ||
543
- node.metadata?.octane_primitive_value
551
+ (node.metadata?.octane_primitive_value &&
552
+ !(retainLocalCapability && node.metadata?.octane_primitive_local_value))
544
553
  ) {
545
554
  return false;
546
555
  }
@@ -551,22 +560,26 @@ function canCarryDirectSignalHandle(node, conservativeResult = false) {
551
560
  node.type === 'ParenthesizedExpression' ||
552
561
  node.type === 'ChainExpression'
553
562
  ) {
554
- return canCarryDirectSignalHandle(node.expression, conservativeResult);
563
+ return canCarryDirectSignalHandle(node.expression, conservativeResult, retainLocalCapability);
555
564
  }
556
565
  if (node.type === 'ConditionalExpression') {
557
566
  return (
558
- canCarryDirectSignalHandle(node.consequent, conservativeResult) ||
559
- canCarryDirectSignalHandle(node.alternate, conservativeResult)
567
+ canCarryDirectSignalHandle(node.consequent, conservativeResult, retainLocalCapability) ||
568
+ canCarryDirectSignalHandle(node.alternate, conservativeResult, retainLocalCapability)
560
569
  );
561
570
  }
562
571
  if (node.type === 'LogicalExpression') {
563
572
  return (
564
- canCarryDirectSignalHandle(node.left, conservativeResult) ||
565
- canCarryDirectSignalHandle(node.right, conservativeResult)
573
+ canCarryDirectSignalHandle(node.left, conservativeResult, retainLocalCapability) ||
574
+ canCarryDirectSignalHandle(node.right, conservativeResult, retainLocalCapability)
566
575
  );
567
576
  }
568
577
  if (node.type === 'SequenceExpression') {
569
- return canCarryDirectSignalHandle(node.expressions.at(-1), conservativeResult);
578
+ return canCarryDirectSignalHandle(
579
+ node.expressions.at(-1),
580
+ conservativeResult,
581
+ retainLocalCapability,
582
+ );
570
583
  }
571
584
  if (
572
585
  !conservativeResult &&
@@ -652,7 +665,16 @@ function componentInvocationSite(ctx, node) {
652
665
  }
653
666
 
654
667
  function markDirectSignalBinding(binding, ctx, origin, kind) {
655
- if (!canCarryDirectSignalHandle(binding.expr)) return binding;
668
+ if (!canCarryDirectSignalHandle(binding.expr)) {
669
+ // Newly certified locals still retain the prior potential capability:
670
+ // opaque events can import instance models after their first mount. A
671
+ // primitive result removes this adapter, not structural owner identity.
672
+ if (canCarryDirectSignalHandle(binding.expr, false, true)) {
673
+ ctx.signalBindingsUsed = true;
674
+ if (isDirectSignalHandleExpression(binding.expr)) ctx.signalBindingsEager = true;
675
+ }
676
+ return binding;
677
+ }
656
678
  ctx.signalBindingsUsed = true;
657
679
  if (isDirectSignalHandleExpression(binding.expr)) ctx.signalBindingsEager = true;
658
680
  return {
@@ -664,6 +686,7 @@ function markDirectSignalBinding(binding, ctx, origin, kind) {
664
686
 
665
687
  function ssrSignalValue(node, ctx, origin, capability = false) {
666
688
  if (!(capability ? canCarryDirectSignalHandle(node) : isDirectSignalHandleExpression(node))) {
689
+ if (capability && canCarryDirectSignalHandle(node, false, true)) ctx.signalBindingsUsed = true;
667
690
  return node;
668
691
  }
669
692
  ctx.signalBindingsUsed = true;
@@ -1401,6 +1424,7 @@ const NATIVE_READ_RUNTIME_HELPERS = new Set([
1401
1424
  'nativeCreateScopedElement',
1402
1425
  ]);
1403
1426
  const INTERNAL_CLIENT_RUNTIME_HELPERS = new Set([
1427
+ '__createCompiledContext',
1404
1428
  'isContext',
1405
1429
  'bindPresentationView',
1406
1430
  'beginPresentationHydration',
@@ -1420,6 +1444,7 @@ const INTERNAL_CLIENT_RUNTIME_HELPERS = new Set([
1420
1444
  'bindSignalText',
1421
1445
  'bindSignalChild',
1422
1446
  'bindSignalAttribute',
1447
+ 'hydrateClaimedBindingCaches',
1423
1448
  'bindSignalValue',
1424
1449
  'bindSignalChecked',
1425
1450
  'bindSignalHostPropSources',
@@ -9921,6 +9946,12 @@ function compileInternal(
9921
9946
  options?.rendererBoundaries == null &&
9922
9947
  options?.rendererRegistry == null;
9923
9948
  const authoredVoidRootIds = new Set();
9949
+ const privateCompiledContexts = localVoidRootsEnabled
9950
+ ? findPrivateCompiledContexts(ast)
9951
+ : new Map();
9952
+ const splitPrivateContexts = localVoidRootsEnabled
9953
+ ? privateCompiledContextsForHydrateAst(parsedAst)
9954
+ : null;
9924
9955
  if (
9925
9956
  localVoidRootsEnabled &&
9926
9957
  ast.body.some(
@@ -10066,6 +10097,9 @@ function compileInternal(
10066
10097
  nativeChangeClassifications: nativeChangeAnalysis.classifications,
10067
10098
  dev: devEnabled,
10068
10099
  profile: profileEnabled,
10100
+ compiledHydrateTemplates: localVoidRootsEnabled,
10101
+ compiledSplitHydrateTags: compiledSplitHydrateTagsForAst(parsedAst),
10102
+ privateSplitContextProviders: splitPrivateContexts?.providers,
10069
10103
  autoMemo: autoMemoEnabled,
10070
10104
  strongMemo: strongMemoEnabled,
10071
10105
  nativeReads: options?.nativeReads === true,
@@ -10450,6 +10484,18 @@ function compileInternal(
10450
10484
  );
10451
10485
  }
10452
10486
  }
10487
+ if (privateCompiledContexts.size > 0 || splitPrivateContexts?.callees.size > 0) {
10488
+ const helper = '__createCompiledContext';
10489
+ const alias = allocCompilerName(ctx, rtAlias(helper));
10490
+ (ctx.privateRuntimeAliases ??= new Map()).set(helper, alias);
10491
+ ctx.runtimeNeeded.add(helper);
10492
+ const callees = new Set([
10493
+ ...privateCompiledContexts.values(),
10494
+ ...(splitPrivateContexts?.callees ?? []),
10495
+ ]);
10496
+ ast = mapAst(ast, (node) => (callees.has(node) ? { ...node, name: alias } : null));
10497
+ ctx.privateCompiledContexts = new Set(privateCompiledContexts.keys());
10498
+ }
10453
10499
  // Return-based JSX functions never attach fetch-tree warm plans, and a sole
10454
10500
  // same-module component already rejects a self-only warm edge below. Avoid a
10455
10501
  // whole-module graph walk unless a compiled-void body can actually reach a
@@ -12719,8 +12765,10 @@ function ssrEmitElement(node, ctx, name, inlinedSubs, parentNs, cssHash, compone
12719
12765
  );
12720
12766
  const hostSignalSite = directSignalSite(ctx, node, 'binding');
12721
12767
  let directSignalControlSite = null;
12768
+ let directSignalControlValues = false;
12722
12769
  const markDirectControl = (expression, origin) => {
12723
- if (!canCarryDirectSignalHandle(expression)) return expression;
12770
+ const carriesHandle = canCarryDirectSignalHandle(expression);
12771
+ if (!carriesHandle && !canCarryDirectSignalHandle(expression, false, true)) return expression;
12724
12772
  const site = firstSpreadIdx === -1 ? directSignalSite(ctx, node, 'input') : hostSignalSite;
12725
12773
  if (directSignalControlSite === null) {
12726
12774
  if (directAttributeIdentities.has('data-octane-input')) {
@@ -12732,10 +12780,13 @@ function ssrEmitElement(node, ctx, name, inlinedSubs, parentNs, cssHash, compone
12732
12780
  bakeLit(` data-octane-input="${escapeAttr(site)}"`, 'data-octane-input', null, null);
12733
12781
  }
12734
12782
  ctx.signalBindingsUsed = true;
12783
+ if (!carriesHandle) return expression;
12784
+ directSignalControlValues = true;
12735
12785
  ctx.runtimeNeeded.add('ssrSignalControlValue');
12736
12786
  return ssrCall('ssrSignalControlValue', [expression, b.literal(site)], origin);
12737
12787
  };
12738
12788
  if (firstSpreadIdx !== -1 && (tag === 'input' || tag === 'textarea' || tag === 'select')) {
12789
+ directSignalControlValues = true;
12739
12790
  directSignalControlSite = hostSignalSite;
12740
12791
  if (directAttributeIdentities.has('data-octane-input')) {
12741
12792
  throw new Error(
@@ -13414,7 +13465,7 @@ function ssrEmitElement(node, ctx, name, inlinedSubs, parentNs, cssHash, compone
13414
13465
  parts.push(singleDirectAttribute);
13415
13466
  }
13416
13467
  let signalControlAttrs = null;
13417
- if (directSignalControlSite !== null) {
13468
+ if (directSignalControlValues) {
13418
13469
  ctx.runtimeNeeded.add('ssrSignalControlAttrs');
13419
13470
  signalControlAttrs = ssrCall('ssrSignalControlAttrs', [b.array(formControlSources)], node);
13420
13471
  }
@@ -15540,6 +15591,8 @@ function preparePresentationHydration(body, node, ctx, hostEnd) {
15540
15591
  * bodies. `cssHash` selects the enclosing scoped-style expression fallback.
15541
15592
  */
15542
15593
  function compileFunctionBody(node, ctx, name, parentNs = 'html', cssHash = null, options = null) {
15594
+ const previousScalarBindingClaims = ctx.scalarBindingClaims;
15595
+ ctx.scalarBindingClaims = node._octaneScalarBindingClaims;
15543
15596
  const previousPresentationHydration = ctx.presentationHydration;
15544
15597
  ctx.presentationHydration = node._octanePresentationHydration;
15545
15598
  const returnedOutput = options?.returnedOutput === true;
@@ -16153,6 +16206,7 @@ function compileFunctionBody(node, ctx, name, parentNs = 'html', cssHash = null,
16153
16206
  ctx,
16154
16207
  presentationHostEnd,
16155
16208
  );
16209
+ ctx.scalarBindingClaims = previousScalarBindingClaims;
16156
16210
  ctx.presentationHydration = previousPresentationHydration;
16157
16211
  const emittedFunction = b.function_declaration(
16158
16212
  b.id(name, node.id ?? node),
@@ -18299,7 +18353,12 @@ function buildWarmArtifacts(node, ctx, componentName, creations, warmChildren) {
18299
18353
  inheritOriginLoc(
18300
18354
  b.call(
18301
18355
  warmChildAlias,
18302
- b.id(w.compName),
18356
+ b.id(
18357
+ ctx.compiledSplitHydrateTags?.has(w.origin.openingElement?.name) &&
18358
+ isCompiledHydrateTemplate(w.origin, ctx, w.origin.openingElement.attributes)
18359
+ ? requireCompiledHydrateAlias(ctx)
18360
+ : w.compName,
18361
+ ),
18303
18362
  b.object(
18304
18363
  w.props.map((p) =>
18305
18364
  b.prop(
@@ -20107,13 +20166,22 @@ function memberProps(hn, src) {
20107
20166
  // primitive value proofs separately from the renderer's text assertions:
20108
20167
  // an authored `as string` still permits a signal handle at runtime.
20109
20168
  ...(isPrimitiveValueExpression(src)
20110
- ? { metadata: { ...src?.metadata, octane_primitive_value: true } }
20169
+ ? {
20170
+ metadata: {
20171
+ ...src?.metadata,
20172
+ octane_primitive_value: true,
20173
+ ...(canCarryDirectSignalHandle(src, false, true) && !canCarryDirectSignalHandle(src)
20174
+ ? { octane_primitive_local_value: true }
20175
+ : null),
20176
+ },
20177
+ }
20111
20178
  : null),
20112
20179
  };
20113
20180
  }
20114
20181
 
20115
- function isPrimitiveValueExpression(node) {
20182
+ function isPrimitiveValueExpression(node, proveExpression = null) {
20116
20183
  if (!node || typeof node !== 'object') return false;
20184
+ if (proveExpression?.(node) === true) return true;
20117
20185
  if (
20118
20186
  node.type === 'TSAsExpression' ||
20119
20187
  node.type === 'TSTypeAssertion' ||
@@ -20123,7 +20191,7 @@ function isPrimitiveValueExpression(node) {
20123
20191
  node.type === 'ParenthesizedExpression' ||
20124
20192
  node.type === 'ChainExpression'
20125
20193
  ) {
20126
- return isPrimitiveValueExpression(node.expression);
20194
+ return isPrimitiveValueExpression(node.expression, proveExpression);
20127
20195
  }
20128
20196
  if (
20129
20197
  node.metadata?.octane_string_child ||
@@ -20153,17 +20221,21 @@ function isPrimitiveValueExpression(node) {
20153
20221
  }
20154
20222
  if (node.type === 'ConditionalExpression') {
20155
20223
  return (
20156
- isPrimitiveValueExpression(node.consequent) && isPrimitiveValueExpression(node.alternate)
20224
+ isPrimitiveValueExpression(node.consequent, proveExpression) &&
20225
+ isPrimitiveValueExpression(node.alternate, proveExpression)
20157
20226
  );
20158
20227
  }
20159
20228
  if (node.type === 'LogicalExpression') {
20160
- return isPrimitiveValueExpression(node.left) && isPrimitiveValueExpression(node.right);
20229
+ return (
20230
+ isPrimitiveValueExpression(node.left, proveExpression) &&
20231
+ isPrimitiveValueExpression(node.right, proveExpression)
20232
+ );
20161
20233
  }
20162
20234
  if (node.type === 'SequenceExpression') {
20163
- return isPrimitiveValueExpression(node.expressions.at(-1));
20235
+ return isPrimitiveValueExpression(node.expressions.at(-1), proveExpression);
20164
20236
  }
20165
20237
  if (node.type === 'AssignmentExpression') {
20166
- if (node.operator === '=') return isPrimitiveValueExpression(node.right);
20238
+ if (node.operator === '=') return isPrimitiveValueExpression(node.right, proveExpression);
20167
20239
  return node.operator === '+=' || NUMERIC_TEXT_OPERATORS.has(node.operator.slice(0, -1));
20168
20240
  }
20169
20241
  return false;
@@ -23384,10 +23456,12 @@ function applyStringChildProofs(ast, source, filename, facts) {
23384
23456
  source.includes('BigInt') ||
23385
23457
  source.includes('Date') ||
23386
23458
  source.includes('\\u');
23459
+ const inspectPrimitiveLocals = source.includes('const');
23387
23460
  if (
23388
23461
  (typedRanges === null || typedRanges.size === 0) &&
23389
23462
  (primitiveRanges === null || primitiveRanges.size === 0) &&
23390
- !inspectIntrinsicCalls
23463
+ !inspectIntrinsicCalls &&
23464
+ !inspectPrimitiveLocals
23391
23465
  ) {
23392
23466
  return ast;
23393
23467
  }
@@ -23395,7 +23469,12 @@ function applyStringChildProofs(ast, source, filename, facts) {
23395
23469
  const primitiveProofs = new Set();
23396
23470
  const intrinsicCalls = [];
23397
23471
  const writes = [];
23472
+ let intrinsicMutationReference = false;
23473
+ const intrinsicMutationReferences = [];
23474
+ const intrinsicAliases = [];
23398
23475
  const ambientIntrinsicValues = new Set();
23476
+ const constantDeclarations = [];
23477
+ const references = [];
23399
23478
  const seen = new WeakSet();
23400
23479
  const collect = (node, parent = null, key = null) => {
23401
23480
  if (node === null || typeof node !== 'object') return;
@@ -23405,6 +23484,20 @@ function applyStringChildProofs(ast, source, filename, facts) {
23405
23484
  }
23406
23485
  if (seen.has(node)) return;
23407
23486
  seen.add(node);
23487
+ if (inspectPrimitiveLocals) {
23488
+ if (
23489
+ node.type === 'VariableDeclarator' &&
23490
+ parent?.type === 'VariableDeclaration' &&
23491
+ parent.kind === 'const' &&
23492
+ parent.declare !== true &&
23493
+ node.id?.type === 'Identifier' &&
23494
+ node.init
23495
+ ) {
23496
+ constantDeclarations.push(node);
23497
+ } else if (node.type === 'Identifier') {
23498
+ references.push({ node, parent, key });
23499
+ }
23500
+ }
23408
23501
  if (
23409
23502
  (typedRanges !== null || primitiveRanges !== null) &&
23410
23503
  node.type === 'JSXExpressionContainer' &&
@@ -23421,9 +23514,43 @@ function applyStringChildProofs(ast, source, filename, facts) {
23421
23514
  if (primitiveRanges?.delete(range)) primitiveProofs.add(expr);
23422
23515
  }
23423
23516
  if (inspectIntrinsicCalls) {
23517
+ if (
23518
+ node.type === 'MemberExpression' ||
23519
+ (node.type === 'Property' && parent?.type === 'ObjectPattern')
23520
+ ) {
23521
+ const property = node.type === 'MemberExpression' ? node.property : node.key;
23522
+ const method = node.computed ? property?.value : (property?.name ?? property?.value);
23523
+ if (
23524
+ INTRINSIC_MUTATION_METHODS.has(method) ||
23525
+ (node.computed && property?.type !== 'Literal')
23526
+ ) {
23527
+ // Unknown computed references may extract a mutator or sit under a
23528
+ // TypeScript/optional-chain wrapper before invocation. Decline the new
23529
+ // intrinsic-local proof even for unrelated dynamic property reads;
23530
+ // this is rejection only, not built-in name admission.
23531
+ intrinsicMutationReference = true;
23532
+ }
23533
+ }
23534
+ if (
23535
+ node.type === 'VariableDeclarator' &&
23536
+ parent?.type === 'VariableDeclaration' &&
23537
+ parent.kind === 'const' &&
23538
+ node.id?.type === 'Identifier' &&
23539
+ node.init
23540
+ ) {
23541
+ intrinsicAliases.push(node);
23542
+ }
23543
+ if (node.type === 'MemberExpression' && isPossibleIntrinsicMutator(node)) {
23544
+ intrinsicMutationReferences.push([node.object, node, parent]);
23545
+ } else if (node.type === 'VariableDeclarator' && node.id?.type === 'ObjectPattern') {
23546
+ for (const property of node.id.properties || []) {
23547
+ if (property.type === 'Property' && isPossibleIntrinsicMutator(property)) {
23548
+ intrinsicMutationReferences.push([node.init, property]);
23549
+ }
23550
+ }
23551
+ }
23424
23552
  if (
23425
23553
  node.type === 'CallExpression' &&
23426
- node.optional !== true &&
23427
23554
  node.callee?.type === 'Identifier' &&
23428
23555
  TEXT_INTRINSICS.has(node.callee.name)
23429
23556
  ) {
@@ -23469,7 +23596,8 @@ function applyStringChildProofs(ast, source, filename, facts) {
23469
23596
  let lexical = null;
23470
23597
  if (
23471
23598
  intrinsicCalls.length > 0 ||
23472
- ((stringProofs.size > 0 || primitiveProofs.size > 0) && writes.length > 0)
23599
+ ((stringProofs.size > 0 || primitiveProofs.size > 0) &&
23600
+ (writes.length > 0 || intrinsicMutationReferences.length > 0))
23473
23601
  ) {
23474
23602
  // The existing scope analysis understands var hoisting, parameter defaults,
23475
23603
  // imports, catch bindings, and TSRX @for/@try scopes. Pay for it only when
@@ -23485,17 +23613,206 @@ function applyStringChildProofs(ast, source, filename, facts) {
23485
23613
  }
23486
23614
  }
23487
23615
  if (lexical !== null) {
23616
+ const aliases = new WeakMap();
23617
+ for (const declaration of intrinsicAliases) {
23618
+ const scope = lexical.resolveBinding(
23619
+ lexical.nodeScopes.get(declaration.id),
23620
+ declaration.id.name,
23621
+ )?.scope;
23622
+ if (scope === undefined) continue;
23623
+ let values = aliases.get(scope);
23624
+ if (values === undefined) aliases.set(scope, (values = new Map()));
23625
+ values.set(declaration.id.name, declaration.init);
23626
+ }
23627
+ const initializer = (node) => {
23628
+ const scope = lexical.resolveBinding(lexical.nodeScopes.get(node), node.name)?.scope;
23629
+ return scope === undefined ? undefined : aliases.get(scope)?.get(node.name);
23630
+ };
23631
+ const intrinsicMemberName = (node) => {
23632
+ const property = node.computed ? unwrapTsExpr(node.property) : node.property;
23633
+ return node.computed
23634
+ ? property?.type === 'Literal' && typeof property.value === 'string'
23635
+ ? property.value
23636
+ : null
23637
+ : property?.type === 'Identifier'
23638
+ ? property.name
23639
+ : null;
23640
+ };
23641
+ const globalOrigin = (expression, seen = new Set(), constructors = false) => {
23642
+ const node = unwrapTsExpr(expression);
23643
+ if (!node || seen.has(node)) return null;
23644
+ seen.add(node);
23645
+ if (node.type === 'Identifier') {
23646
+ const scope = lexical.nodeScopes.get(node);
23647
+ if (scope === undefined) return null;
23648
+ if (!lexical.isBound(scope, node.name)) {
23649
+ return INLINE_INTRINSIC_MUTATION_GLOBALS.has(node.name) ||
23650
+ (constructors && TEXT_INTRINSICS.has(node.name))
23651
+ ? node.name
23652
+ : null;
23653
+ }
23654
+ return globalOrigin(initializer(node), seen, constructors);
23655
+ }
23656
+ if (node.type === 'ChainExpression') return globalOrigin(node.expression, seen, constructors);
23657
+ if (node.type === 'MemberExpression') {
23658
+ const name = intrinsicMemberName(node);
23659
+ if (name !== 'Object' && name !== 'Reflect' && !(constructors && TEXT_INTRINSICS.has(name)))
23660
+ return null;
23661
+ const origin = globalOrigin(node.object, seen);
23662
+ return origin !== null && INLINE_INTRINSIC_GLOBAL_RECEIVERS.has(origin) ? name : null;
23663
+ }
23664
+ return null;
23665
+ };
23666
+ const freshTarget = (expression, seen = new Set()) => {
23667
+ const node = unwrapTsExpr(expression);
23668
+ if (!node || seen.has(node)) return false;
23669
+ seen.add(node);
23670
+ if (node.type === 'ObjectExpression' || node.type === 'ArrayExpression') return true;
23671
+ return node.type === 'Identifier' && freshTarget(initializer(node), seen);
23672
+ };
23673
+ const visibleMutation =
23674
+ intrinsicMutationReferences.some(([receiver, reference, parent]) => {
23675
+ const origin = globalOrigin(receiver);
23676
+ const key = reference.type === 'Property' ? reference.key : reference.property;
23677
+ const property = reference.computed ? unwrapTsExpr(key) : key;
23678
+ const method = reference.computed ? property?.value : (property?.name ?? property?.value);
23679
+ if (origin === 'Object' || origin === 'Reflect') {
23680
+ // A normal native call targeting a fresh literal cannot directly write
23681
+ // a global constructor. Unknown getter/callback effects retain the
23682
+ // existing builtin assumptions; wrapped/extracted calls fail closed.
23683
+ const target = parent?.arguments?.[0];
23684
+ return !(
23685
+ parent?.type === 'CallExpression' &&
23686
+ parent.optional !== true &&
23687
+ parent.callee === reference &&
23688
+ reference.optional !== true &&
23689
+ INLINE_INTRINSIC_MUTATION_METHODS.has(method) &&
23690
+ freshTarget(target)
23691
+ );
23692
+ }
23693
+ return (
23694
+ origin !== null &&
23695
+ INLINE_INTRINSIC_GLOBAL_RECEIVERS.has(origin) &&
23696
+ (method === '__defineGetter__' ||
23697
+ method === '__defineSetter__' ||
23698
+ (reference.computed && property?.type !== 'Literal'))
23699
+ );
23700
+ }) ||
23701
+ writes.some((target) => {
23702
+ const node = unwrapTsExpr(target);
23703
+ if (node?.type !== 'MemberExpression') return false;
23704
+ const name = node.computed ? node.property?.value : node.property?.name;
23705
+ if (!TEXT_INTRINSICS.has(name) && !(node.computed && node.property?.type !== 'Literal'))
23706
+ return false;
23707
+ const origin = globalOrigin(node.object);
23708
+ return origin !== null && INLINE_INTRINSIC_GLOBAL_RECEIVERS.has(origin);
23709
+ });
23710
+ const unsafeCalls = new WeakSet();
23488
23711
  for (const call of intrinsicCalls) {
23489
23712
  const name = call.callee.name;
23490
23713
  if (ambientIntrinsicValues.has(name)) continue;
23491
23714
  const scope = lexical.nodeScopes.get(call);
23492
23715
  if (scope !== undefined && !lexical.isBound(scope, name)) {
23716
+ if (visibleMutation) {
23717
+ unsafeCalls.add(call);
23718
+ continue;
23719
+ }
23720
+ if (call.optional === true) continue;
23493
23721
  if (name === 'String' || name === 'Date') stringProofs.add(call);
23494
23722
  else primitiveProofs.add(call);
23495
23723
  }
23496
23724
  }
23725
+ if (visibleMutation) {
23726
+ // TypeScript still describes the built-in return type after an asserted
23727
+ // replacement. Drop only supplied proofs that depend on these calls;
23728
+ // unrelated typed scalars and JavaScript's own coercion guarantees survive.
23729
+ const unsafeProof = (node, seen = new WeakSet()) => {
23730
+ if (!node || typeof node !== 'object' || seen.has(node)) return false;
23731
+ seen.add(node);
23732
+ if (unsafeCalls.has(node)) return true;
23733
+ if (node.type === 'CallExpression') {
23734
+ let callee = unwrapTsExpr(node.callee);
23735
+ while (callee?.type === 'ChainExpression') callee = unwrapTsExpr(callee.expression);
23736
+ if (callee?.type === 'MemberExpression') {
23737
+ const method = intrinsicMemberName(callee);
23738
+ if (method === 'call' || method === 'apply') callee = callee.object;
23739
+ }
23740
+ // Supplied facts may describe a saved constructor or its Function
23741
+ // call/apply result. Invalidation grants no new primitive admission.
23742
+ if (TEXT_INTRINSICS.has(globalOrigin(callee, new Set(), true))) return true;
23743
+ }
23744
+ if (node.type === 'Identifier' && unsafeProof(initializer(node), seen)) return true;
23745
+ if (Array.isArray(node)) return node.some((child) => unsafeProof(child, seen));
23746
+ for (const key in node) {
23747
+ if (AST_WALK_SKIP_KEYS.has(key)) continue;
23748
+ if (unsafeProof(node[key], seen)) return true;
23749
+ }
23750
+ return false;
23751
+ };
23752
+ for (const proofs of [stringProofs, primitiveProofs]) {
23753
+ for (const proof of proofs) if (unsafeProof(proof)) proofs.delete(proof);
23754
+ }
23755
+ }
23497
23756
  }
23498
- if (stringProofs.size === 0 && primitiveProofs.size === 0) return ast;
23757
+ const valueProofs = new Set();
23758
+ if (
23759
+ constantDeclarations.length > 0 &&
23760
+ (stringProofs.size > 0 ||
23761
+ primitiveProofs.size > 0 ||
23762
+ constantDeclarations.some((declaration) => isPrimitiveValueExpression(declaration.init)))
23763
+ ) {
23764
+ lexical ??= createLexicalAnalysis(ast);
23765
+ // A local alias can mutate a global constructor without spelling its
23766
+ // global receiver. This check only declines new local intrinsic facts;
23767
+ // operator/template primitives and existing child proofs remain.
23768
+ const intrinsicLocalResultsSafe =
23769
+ !intrinsicMutationReference && !writes.some(mayWriteTextIntrinsicMember);
23770
+ const reassigned = collectReassignedBindings(ast);
23771
+ const declarationsByScope = new Map();
23772
+ for (const declaration of constantDeclarations) {
23773
+ if (reassigned.has(declaration.id)) continue;
23774
+ const scope = lexical.nodeScopes.get(declaration.id);
23775
+ if (scope === undefined) continue;
23776
+ const binding = lexical.resolveBinding(scope, declaration.id.name);
23777
+ if (binding === null) continue;
23778
+ let declarations = declarationsByScope.get(binding.scope);
23779
+ if (declarations === undefined) {
23780
+ declarations = new Map();
23781
+ declarationsByScope.set(binding.scope, declarations);
23782
+ }
23783
+ declarations.set(declaration.id.name, declaration);
23784
+ }
23785
+ const proven = new Map();
23786
+ const visiting = new Set();
23787
+ const primitive = (node) => isPrimitiveValueExpression(node, proveLocal);
23788
+ const proveLocal = (node) => {
23789
+ if (intrinsicLocalResultsSafe && (stringProofs.has(node) || primitiveProofs.has(node))) {
23790
+ return true;
23791
+ }
23792
+ if (node.type === 'Identifier') {
23793
+ const scope = lexical.nodeScopes.get(node);
23794
+ const binding = scope === undefined ? null : lexical.resolveBinding(scope, node.name);
23795
+ const declaration = declarationsByScope.get(binding?.scope)?.get(node.name);
23796
+ if (declaration === undefined || visiting.has(declaration)) return false;
23797
+ if (proven.has(declaration)) return proven.get(declaration);
23798
+ visiting.add(declaration);
23799
+ const result = primitive(declaration.init);
23800
+ visiting.delete(declaration);
23801
+ proven.set(declaration, result);
23802
+ return result;
23803
+ }
23804
+ return false;
23805
+ };
23806
+ // A value proof follows the lexical binding and its immutable initializer,
23807
+ // never a TS annotation or a renderer's authored text assertion. Reads and
23808
+ // throws still occur in setup; primitive results can contain native reads.
23809
+ for (const { node, parent, key } of references) {
23810
+ if (isIdentifierReference(node, parent, key, lexical) && primitive(node)) {
23811
+ valueProofs.add(node);
23812
+ }
23813
+ }
23814
+ }
23815
+ if (stringProofs.size === 0 && primitiveProofs.size === 0 && valueProofs.size === 0) return ast;
23499
23816
  const rewritten = new WeakMap();
23500
23817
  const rewrite = (node) => {
23501
23818
  if (node === null || typeof node !== 'object') return node;
@@ -23521,7 +23838,18 @@ function applyStringChildProofs(ast, source, filename, facts) {
23521
23838
  out[key] = next;
23522
23839
  }
23523
23840
  }
23524
- if (stringProofs.has(node)) {
23841
+ if (valueProofs.has(node)) {
23842
+ out = {
23843
+ ...out,
23844
+ metadata: {
23845
+ ...out.metadata,
23846
+ octane_primitive_value: true,
23847
+ octane_primitive_local_value: true,
23848
+ ...(stringProofs.has(node) ? { octane_string_child: true } : null),
23849
+ ...(primitiveProofs.has(node) ? { octane_primitive_text_child: true } : null),
23850
+ },
23851
+ };
23852
+ } else if (stringProofs.has(node)) {
23525
23853
  out = { ...out, metadata: { ...out.metadata, octane_string_child: true } };
23526
23854
  } else if (primitiveProofs.has(node)) {
23527
23855
  out = { ...out, metadata: { ...out.metadata, octane_primitive_text_child: true } };
@@ -23534,20 +23862,73 @@ function applyStringChildProofs(ast, source, filename, facts) {
23534
23862
  }
23535
23863
 
23536
23864
  const TEXT_INTRINSICS = new Set(['String', 'Number', 'BigInt', 'Date']);
23865
+ const INTRINSIC_MUTATION_METHODS = new Set([
23866
+ 'assign',
23867
+ 'defineProperty',
23868
+ 'defineProperties',
23869
+ 'set',
23870
+ '__defineGetter__',
23871
+ '__defineSetter__',
23872
+ 'setPrototypeOf',
23873
+ 'deleteProperty',
23874
+ ]);
23875
+
23876
+ function mayWriteTextIntrinsicMember(target) {
23877
+ target = unwrapTsExpr(target);
23878
+ if (!target || typeof target !== 'object') return false;
23879
+ if (target.type === 'AssignmentPattern') return mayWriteTextIntrinsicMember(target.left);
23880
+ if (target.type === 'MemberExpression') {
23881
+ return target.computed
23882
+ ? target.property?.type !== 'Literal' || TEXT_INTRINSICS.has(target.property.value)
23883
+ : TEXT_INTRINSICS.has(target.property?.name);
23884
+ }
23885
+ if (target.type === 'RestElement') return mayWriteTextIntrinsicMember(target.argument);
23886
+ if (target.type === 'ArrayPattern') {
23887
+ return (target.elements || []).some(mayWriteTextIntrinsicMember);
23888
+ }
23889
+ if (target.type === 'ObjectPattern') {
23890
+ return (target.properties || []).some((property) =>
23891
+ mayWriteTextIntrinsicMember(property.argument ?? property.value),
23892
+ );
23893
+ }
23894
+ return false;
23895
+ }
23896
+
23897
+ const INLINE_INTRINSIC_MUTATION_METHODS = new Set([
23898
+ 'assign',
23899
+ 'defineProperty',
23900
+ 'defineProperties',
23901
+ 'set',
23902
+ '__defineGetter__',
23903
+ '__defineSetter__',
23904
+ 'setPrototypeOf',
23905
+ 'deleteProperty',
23906
+ ]);
23907
+ const INLINE_INTRINSIC_GLOBAL_RECEIVERS = new Set(['globalThis', 'window', 'self', 'global']);
23908
+ const INLINE_INTRINSIC_MUTATION_GLOBALS = new Set([
23909
+ 'Object',
23910
+ 'Reflect',
23911
+ ...INLINE_INTRINSIC_GLOBAL_RECEIVERS,
23912
+ ]);
23913
+
23914
+ // Inspect the reference itself: TS/optional wrappers and extracted methods may
23915
+ // hide its eventual call. Lexical receiver checks keep ordinary computed reads
23916
+ // and application .set methods from invalidating intrinsic-result proofs.
23917
+ function isPossibleIntrinsicMutator(node) {
23918
+ const key = node.type === 'Property' ? node.key : node.property;
23919
+ const property = node.computed ? unwrapTsExpr(key) : key;
23920
+ const name = node.computed ? property?.value : (property?.name ?? property?.value);
23921
+ return (
23922
+ INLINE_INTRINSIC_MUTATION_METHODS.has(name) || (node.computed && property?.type !== 'Literal')
23923
+ );
23924
+ }
23537
23925
 
23538
23926
  // A visible replacement of a global constructor invalidates inferred text
23539
23927
  // proofs for the module. Calls still evaluate the authored callee: a replacement
23540
23928
  // may return an element rather than the built-in's primitive result.
23541
23929
  function writesGlobalTextIntrinsic(target, lexical) {
23930
+ target = unwrapTsExpr(target);
23542
23931
  if (!target || typeof target !== 'object') return false;
23543
- if (
23544
- target.type === 'TSAsExpression' ||
23545
- target.type === 'TSTypeAssertion' ||
23546
- target.type === 'TSNonNullExpression' ||
23547
- target.type === 'ParenthesizedExpression'
23548
- ) {
23549
- return writesGlobalTextIntrinsic(target.expression, lexical);
23550
- }
23551
23932
  const unbound = (node, name) => {
23552
23933
  const scope = lexical.nodeScopes.get(node);
23553
23934
  return scope !== undefined && !lexical.isBound(scope, name);
@@ -25113,6 +25494,69 @@ function planJsx(
25113
25494
  if (b.deferred) everyRenderLines.push(updateEmit);
25114
25495
  else updateLines.push(updateEmit);
25115
25496
  }
25497
+ if (ctx.scalarBindingClaims) {
25498
+ // Only opted-in scalar views can retain another writer's publication at
25499
+ // hydration. Record their existing cache fields; ordinary output is unchanged.
25500
+ const fields = [];
25501
+ for (const binding of elementBindings) {
25502
+ const key = binding.id;
25503
+ const text = binding.kind === 'textOnlyChild' || binding.kind === 'text';
25504
+ const host = text && !binding.signalDirect ? `_txt$${key}` : `_el$${key}`;
25505
+ if (text && binding.signalDirect)
25506
+ fields.push(bag.letter(`_sig$${key}`), bag.letter(host), '#text-token');
25507
+ if (binding.kind === 'nativeStyle') {
25508
+ fields.push(binding.slotIndex, bag.letter(host), 'style');
25509
+ } else if (binding.kind === 'styleProperties') {
25510
+ for (let i = 0; i < binding.properties.length; i++)
25511
+ fields.push(
25512
+ bag.letter(`_prev$${key}_${i}`),
25513
+ bag.letter(host),
25514
+ `style:${binding.properties[i].name}`,
25515
+ );
25516
+ } else if (binding.kind === 'style') {
25517
+ fields.push(bag.letter(`_sty$${key}`), bag.letter(host), 'style');
25518
+ } else if (
25519
+ text ||
25520
+ ['attr', 'stringData', 'booleanAttr', 'ariaAttr', 'class', 'styleProperty'].includes(
25521
+ binding.kind,
25522
+ )
25523
+ ) {
25524
+ const cache = binding.signalDirect && !text ? `_sig$${key}` : `_prev$${key}`;
25525
+ fields.push(
25526
+ bag.letter(cache),
25527
+ bag.letter(host),
25528
+ text
25529
+ ? '#text'
25530
+ : binding.kind === 'styleProperty'
25531
+ ? `style:${binding.name}`
25532
+ : binding.kind === 'class'
25533
+ ? 'class'
25534
+ : ATTRIBUTE_ALIASES.get(binding.name) || binding.name,
25535
+ );
25536
+ }
25537
+ }
25538
+ if (fields.length) {
25539
+ const name = `_claims$${ctx.nextHelperId++}`;
25540
+ ctx.hoistedHelpers.push(
25541
+ inheritOriginLoc(
25542
+ b.const(name, b.array(fields.map((value) => b.literal(value)))),
25543
+ planOrigin,
25544
+ ),
25545
+ );
25546
+ everyRenderLines.push(
25547
+ inheritOriginLoc(
25548
+ b.stmt(
25549
+ b.call(
25550
+ requireRuntimeForContext(ctx, 'hydrateClaimedBindingCaches'),
25551
+ b.id('__s'),
25552
+ b.id(name),
25553
+ ),
25554
+ ),
25555
+ planOrigin,
25556
+ ),
25557
+ );
25558
+ }
25559
+ }
25116
25560
  if (keyedSelection !== null && single && !noTemplate) {
25117
25561
  // Reuse the ordinary root-class write and its exact bag fields. Updating
25118
25562
  // only the DOM would leave the normal row diff's previous value stale.
@@ -28113,11 +28557,13 @@ function emitElementHtml(
28113
28557
  appendTemplatePart(attrTemplate, ` data-octane-input="${escapeAttr(site)}"`, 'attribute', null);
28114
28558
  };
28115
28559
  const markDirectControl = (binding, expression, origin) => {
28116
- if (!canCarryDirectSignalHandle(expression)) return binding;
28560
+ const carriesHandle = canCarryDirectSignalHandle(expression);
28561
+ if (!carriesHandle && !canCarryDirectSignalHandle(expression, false, true)) return binding;
28117
28562
  const site = directSignalSite(ctx, node, 'input');
28118
28563
  ensureDirectControlSite(site);
28119
28564
  ctx.signalBindingsUsed = true;
28120
28565
  if (isDirectSignalHandleExpression(expression)) ctx.signalBindingsEager = true;
28566
+ if (!carriesHandle) return binding;
28121
28567
  return { ...binding, signalDirect: true, signalSite: site };
28122
28568
  };
28123
28569
  const hostSignalSite = directSignalSite(ctx, node, 'binding');
@@ -30312,6 +30758,59 @@ function collectAutoMemoDependencyExpressions(nodes) {
30312
30758
  };
30313
30759
  }
30314
30760
 
30761
+ function requireCompiledHydrateAlias(ctx) {
30762
+ const helper = '__HydrateCompiled';
30763
+ let alias = ctx.privateRuntimeAliases?.get(helper);
30764
+ if (alias === undefined) {
30765
+ alias = allocCompilerName(ctx, rtAlias(helper));
30766
+ (ctx.privateRuntimeAliases ??= new Map()).set(helper, alias);
30767
+ }
30768
+ ctx.runtimeNeeded.add(helper);
30769
+ return alias;
30770
+ }
30771
+
30772
+ function isPrivateSplitContextProvider(node, ctx) {
30773
+ const tag = node.openingElement?.name ?? node.id;
30774
+ const binding = ctx.privateSplitContextProviders?.get(tag);
30775
+ if (binding === undefined || tag.type !== 'JSXIdentifier' || tag.name !== binding.name)
30776
+ return false;
30777
+ const lexical = (ctx.activityLexical ??= createLexicalAnalysis(ctx.activityModuleAst));
30778
+ if (!lexical.bindingNodes.has(binding)) return false;
30779
+ const owner = lexical.resolveBinding(lexical.nodeScopes.get(binding), binding.name);
30780
+ return (
30781
+ owner !== null &&
30782
+ lexical.resolveBinding(lexical.nodeScopes.get(tag), tag.name)?.scope === owner.scope
30783
+ );
30784
+ }
30785
+
30786
+ function isCompiledHydrateTemplate(node, ctx, attrs) {
30787
+ if (!ctx.compiledHydrateTemplates || ctx._universalRuntimeUnit != null) return false;
30788
+ const tag = node.openingElement?.name ?? node.id;
30789
+ if (
30790
+ (tag?.type !== 'Identifier' && tag?.type !== 'JSXIdentifier') ||
30791
+ ctx.octaneImportLocals?.get(tag.name) !== 'Hydrate'
30792
+ )
30793
+ return false;
30794
+ if (!ctx.compiledSplitHydrateTags?.has(tag)) {
30795
+ for (const attr of attrs) {
30796
+ if (attr.type !== 'Attribute' && attr.type !== 'JSXAttribute') return false;
30797
+ const name = attr.name?.name ?? attr.name;
30798
+ if (
30799
+ typeof name !== 'string' ||
30800
+ name === 'children' ||
30801
+ name === 'fallback' ||
30802
+ name.startsWith('__')
30803
+ )
30804
+ return false;
30805
+ }
30806
+ }
30807
+ const lexical = (ctx.activityLexical ??= createLexicalAnalysis(ctx.activityModuleAst));
30808
+ const scope = lexical.nodeScopes.get(tag);
30809
+ if (scope === undefined) return false;
30810
+ const binding = lexical.resolveBinding(scope, tag.name);
30811
+ return binding?.scope === lexical.rootScope && binding.importSource?.value === 'octane';
30812
+ }
30813
+
30315
30814
  function makeCompCall(
30316
30815
  node,
30317
30816
  ctx,
@@ -30330,7 +30829,7 @@ function makeCompCall(
30330
30829
  const staticFragmentRenderer = node.openingElement?.metadata?.staticFragmentRenderer;
30331
30830
  const activityDescriptor = isActivityLongForm(node, ctx);
30332
30831
  const descriptorConfig = activityDescriptor || hasKeyedSpreadConfig(node);
30333
- const compNode = activityDescriptor
30832
+ let compNode = activityDescriptor
30334
30833
  ? inheritOriginLoc(b.id(requireRuntimeForContext(ctx, 'Activity')), node)
30335
30834
  : staticFragmentRenderer
30336
30835
  ? inheritOriginLoc(b.id(staticFragmentRenderer.name), node.openingElement?.name || node.id)
@@ -30403,6 +30902,7 @@ function makeCompCall(
30403
30902
  // arrow while making its body printable. Whitespace-only JSXText around the
30404
30903
  // arrow is ignored so source indentation doesn't defeat the detection.
30405
30904
  const sourceChildren = node.children || [];
30905
+ let compiledChildren = false;
30406
30906
  const renderPropChild = soleRenderPropChild(sourceChildren);
30407
30907
  if (renderPropChild) {
30408
30908
  hasChildrenProp = true;
@@ -30434,6 +30934,7 @@ function makeCompCall(
30434
30934
  propNodes.push(b.prop('init', b.literal('children'), childrenValue));
30435
30935
  }
30436
30936
  } else {
30937
+ compiledChildren = true;
30437
30938
  // Compile children as a render function: (scope) => { renders JSX into scope }.
30438
30939
  // The function is inlined inside the parent component body so its closures
30439
30940
  // capture the parent's locals (props, state, etc.).
@@ -30524,7 +31025,16 @@ function makeCompCall(
30524
31025
  // elides iff the callee carries the definition-site `$$singleRoot` stamp
30525
31026
  // (docs/comment-marker-elision-plan.md M1).
30526
31027
  let maybeSingleRoot = false;
30527
- if (staticFragmentRenderer) {
31028
+ if (
31029
+ (compiledChildren || ctx.compiledSplitHydrateTags?.has(node.openingElement?.name ?? node.id)) &&
31030
+ isCompiledHydrateTemplate(node, ctx, attrs)
31031
+ ) {
31032
+ compNode = inheritOriginLoc(
31033
+ b.id(requireCompiledHydrateAlias(ctx)),
31034
+ node.openingElement?.name ?? node.id,
31035
+ );
31036
+ voidComponent = true;
31037
+ } else if (staticFragmentRenderer) {
30528
31038
  // The renderer is already a void, hookless component body. A memo boundary
30529
31039
  // would force a full Block and could hide a hookful descendant's update.
30530
31040
  liteEligible = true;
@@ -30638,6 +31148,11 @@ function makeCompCall(
30638
31148
  maybeSingleRoot = callSiteOk;
30639
31149
  }
30640
31150
  const importedBinding = ctx.importedComponentBindings?.get(compName);
31151
+ if (
31152
+ !voidComponent &&
31153
+ (ctx.privateCompiledContexts?.has(compName) || isPrivateSplitContextProvider(node, ctx))
31154
+ )
31155
+ voidComponent = true;
30641
31156
  if (
30642
31157
  !voidComponent &&
30643
31158
  !ctx.hmr &&