octane 0.3.2 → 0.3.3

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.
@@ -21,7 +21,7 @@ __export(version_exports, {
21
21
  version: () => version
22
22
  });
23
23
  module.exports = __toCommonJS(version_exports);
24
- const version = "0.3.2";
24
+ const version = "0.3.3";
25
25
  // Annotate the CommonJS export names for ESM import in node:
26
26
  0 && (module.exports = {
27
27
  version
@@ -30634,7 +30634,7 @@ function autoMemoDependencyOrderKey(original) {
30634
30634
  return astStructuralKey(node);
30635
30635
  }
30636
30636
 
30637
- function collectAutoMemoDependencyExpressions(nodes) {
30637
+ function collectAutoMemoDependencyExpressions(nodes, templateControlFlow = false) {
30638
30638
  const dependencies = new Set();
30639
30639
  const dependencyNodes = new Map();
30640
30640
  const dependencyOrder = new Map();
@@ -30693,6 +30693,19 @@ function collectAutoMemoDependencyExpressions(nodes) {
30693
30693
  node.type === 'LogicalExpression' ||
30694
30694
  node.type === 'ConditionalExpression' ||
30695
30695
  node.type === 'ChainExpression' ||
30696
+ (templateControlFlow &&
30697
+ (node.type === 'JSXIfExpression' ||
30698
+ node.type === 'JSXForExpression' ||
30699
+ node.type === 'JSXSwitchExpression' ||
30700
+ node.type === 'JSXTryExpression' ||
30701
+ node.type === 'IfStatement' ||
30702
+ node.type === 'ForStatement' ||
30703
+ node.type === 'ForOfStatement' ||
30704
+ node.type === 'ForInStatement' ||
30705
+ node.type === 'SwitchStatement' ||
30706
+ node.type === 'TryStatement' ||
30707
+ node.type === 'WhileStatement' ||
30708
+ node.type === 'DoWhileStatement')) ||
30696
30709
  ((node.type === 'MemberExpression' ||
30697
30710
  node.type === 'OptionalMemberExpression' ||
30698
30711
  node.type === 'CallExpression' ||
@@ -30769,6 +30782,38 @@ function requireCompiledHydrateAlias(ctx) {
30769
30782
  return alias;
30770
30783
  }
30771
30784
 
30785
+ function hydrateDiagnosticChildrenCaptures(node, children, ctx) {
30786
+ if (!ctx.dev || ctx.mode === 'server') return undefined;
30787
+ const tag = node.openingElement?.name ?? node.id;
30788
+ if (tag?.type !== 'JSXIdentifier' || ctx.octaneImportLocals?.get(tag.name) !== 'Hydrate')
30789
+ return undefined;
30790
+ const lexical = (ctx.activityLexical ??= createLexicalAnalysis(ctx.activityModuleAst));
30791
+ const binding = lexical.resolveBinding(lexical.nodeScopes.get(tag), tag.name);
30792
+ if (binding?.scope !== lexical.rootScope || binding.importSource?.value !== 'octane')
30793
+ return undefined;
30794
+ const plan = collectAutoMemoDependencyExpressions(children, true);
30795
+ if (!plan.safe || mapCallbackCapturesLexicalReceiver(children)) return null;
30796
+ const free = collectFreeIdentifiers(children, []);
30797
+ const local = collectSubtreeBindings(children, new Set());
30798
+ // A child-local shadow with the same spelling cannot be read from the
30799
+ // enclosing closure. Decline the certificate rather than invent a witness.
30800
+ for (const name of free) if (local.has(name)) return null;
30801
+ const captures = [];
30802
+ const covered = new Set();
30803
+ const dependencyNode = depNodeFor({ autoMemoDepNodes: plan.dependencyNodes });
30804
+ for (const dependency of plan.dependencies) {
30805
+ const expression = dependencyNode(dependency);
30806
+ const roots = collectFreeIdentifiers(expression, []);
30807
+ if (roots.size === 0 || [...roots].some((name) => !free.has(name))) continue;
30808
+ captures.push(expression);
30809
+ for (const name of roots) covered.add(name);
30810
+ }
30811
+ for (const name of free) if (!covered.has(name)) captures.push(b.id(name));
30812
+ // Property reads stay deferred until activation; collecting diagnostic data
30813
+ // must not evaluate a dormant child's getters or call its render function.
30814
+ return inheritOriginLoc(b.arrow([], b.array(captures)), node);
30815
+ }
30816
+
30772
30817
  function isPrivateSplitContextProvider(node, ctx) {
30773
30818
  const tag = node.openingElement?.name ?? node.id;
30774
30819
  const binding = ctx.privateSplitContextProviders?.get(tag);
@@ -30958,7 +31003,8 @@ function makeCompCall(
30958
31003
  ctx.runtimeNeeded.add('markChildrenBlock');
30959
31004
  hasChildrenProp = true;
30960
31005
  const childrenArgs = [b.id(childrenHelperName)];
30961
- if (ctx.autoMemo && ctx.mode !== 'server') {
31006
+ const diagnosticCaptures = hydrateDiagnosticChildrenCaptures(node, children, ctx);
31007
+ if ((ctx.autoMemo && ctx.mode !== 'server') || diagnosticCaptures !== undefined) {
30962
31008
  // These functions close over parent locals and are recreated on every
30963
31009
  // render. A module-owned token distinguishes a real Provider body
30964
31010
  // handoff from fresh captures without invalidating ordinary cache hits.
@@ -30966,6 +31012,8 @@ function makeCompCall(
30966
31012
  ctx.hoistedHelpers.push(inheritOriginLoc(b.const(bodyIdentity, b.object([])), node));
30967
31013
  childrenArgs.push(b.id(bodyIdentity));
30968
31014
  }
31015
+ if (diagnosticCaptures !== undefined)
31016
+ childrenArgs.push(diagnosticCaptures ?? b.literal(null));
30969
31017
  let childrenValue = b.call('_$markChildrenBlock', ...childrenArgs);
30970
31018
  if (ctx.presentationHydration?.structural && node._octaneBindingSite)
30971
31019
  childrenValue = b.call(
package/dist/runtime.d.ts CHANGED
@@ -996,7 +996,7 @@ export declare function markSingleRoot<T extends Function>(component: T): T;
996
996
  * Returns the function for inline use (`{ children: markChildrenBlock(__children$N) }`).
997
997
  * @internal
998
998
  */
999
- export declare function markChildrenBlock<T>(fn: T, body?: object): T;
999
+ export declare function markChildrenBlock<T>(fn: T, body?: object, captures?: (() => readonly unknown[]) | null): T;
1000
1000
  /**
1001
1001
  * Marks a component binding whose authored JSX children must remain inspectable
1002
1002
  * element descriptors. The compiler consumes the call; runtime identity is unchanged.
@@ -1009,6 +1009,36 @@ export declare function descriptorChildren<T>(component: T): T;
1009
1009
  * `<C><D/></C>` (render it): `typeof children === 'function' && !isChildrenBlock(children)`.
1010
1010
  */
1011
1011
  export declare function isChildrenBlock(value: unknown): boolean;
1012
+ type HydrateLoadResult = ComponentBody | {
1013
+ default: ComponentBody;
1014
+ };
1015
+ type InternalHydrateProps = HydrateProps & {
1016
+ /** Compiler-injected split-child loader. */
1017
+ __load?: () => Promise<HydrateLoadResult>;
1018
+ /** Latest lexical values consumed by the compiler-generated split child. */
1019
+ __data?: unknown[];
1020
+ /** Compiler-owned independent island descriptor; the document bootstrap owns activation. */
1021
+ __independent?: unknown;
1022
+ /** Bundler graph edge only. Runtime must never evaluate the lexical parent through it. */
1023
+ __independentLoad?: () => Promise<unknown>;
1024
+ };
1025
+ interface HydrateAttributeSnapshot {
1026
+ props: InternalHydrateProps;
1027
+ ids: RootIdState;
1028
+ contexts: Map<Context<any>, any> | null;
1029
+ }
1030
+ interface InitialHydrateAttribute {
1031
+ server: string | null;
1032
+ next: string | null;
1033
+ suppressed: boolean;
1034
+ checked: boolean;
1035
+ }
1036
+ interface HydrateAttributeProbe {
1037
+ document: Document;
1038
+ originals: WeakMap<Element, Element>;
1039
+ attributes: WeakMap<Element, Map<string, InitialHydrateAttribute>>;
1040
+ boundaries: WeakMap<Element, HydrateAttributeSnapshot>;
1041
+ }
1012
1042
  export declare const Hydrate: ComponentBody<HydrateProps>;
1013
1043
  /** Compiler-owned template children with no authored fallback; never a descriptor entry point. */
1014
1044
  export declare const __HydrateCompiled: ComponentBody<HydrateProps>;
@@ -1289,6 +1319,7 @@ declare class HydrationCapability {
1289
1319
  rootBlock: Block;
1290
1320
  node: Node | null;
1291
1321
  seeds: unknown[] | null;
1322
+ attributeBaselines?: HydrateAttributeProbe;
1292
1323
  depth: number;
1293
1324
  seedCursor: number;
1294
1325
  hasAdjacentRangePair: boolean;