Skip to content

Integration/context system#8

Merged
MarcelOlsen merged 12 commits intomasterfrom
integration/context-system
Jun 17, 2025
Merged

Integration/context system#8
MarcelOlsen merged 12 commits intomasterfrom
integration/context-system

Conversation

@MarcelOlsen
Copy link
Owner

@MarcelOlsen MarcelOlsen commented Jun 17, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a context system with createContext and useContext hooks for managing shared state.
  • Bug Fixes
    • Improved context propagation and reactivity during component rendering and updates.
  • Documentation
    • Updated README with a clear, structured roadmap separating alpha and stable release tracks, detailed phase descriptions, and current progress.
  • Tests
    • Added extensive tests covering context API behavior, dynamic updates, and edge cases.
  • Chores
    • Enhanced package scripts to separate linting, formatting, and checking commands with read-only and write modes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 17, 2025

Warning

Rate limit exceeded

@MarcelOlsen has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 19 minutes and 22 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between c6600ee and d4a0107.

📒 Files selected for processing (1)
  • src/reconciler.ts (8 hunks)

Walkthrough

Alright, chat, this PR is giga-chad level: it slaps a full context API onto MiniReact, wires up the reconciler for context propagation, and drops a massive README overhaul with a split roadmap (alpha/stable). There’s also a new context test suite, and the package scripts get a proper biome glow-up. Absolute banger of a change.

Changes

Files / Areas Change Summary
README.md Major restructure: splits roadmap into alpha/stable tracks, details phase statuses, adds new phases, updates features/tests, simplifies contributing, removes code quality section, and improves wording/formatting.
package.json Expands scripts: adds separate lint, format, and check commands with --write variants; improves structure and clarity.
src/MiniReact.ts Adds context system: global context stack, createContext, useContext, context provider logic, imports/exports for context types, and minor refactor.
src/reconciler.ts Integrates context management: adds push/pop hooks, restores and enhances update logic, manages parent/child references, and context propagation during reconciliation.
src/types.ts Expands types: adds ContextHook, updates hook unions, extends VDOMInstance with context/parent, defines MiniReactContext, and adds UseContextHook type.
tests/MiniReact.context.test.ts New comprehensive test suite: covers context creation, consumption, nested providers, updates, edge cases, and unmount/remount behavior for the context API.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant Provider
    participant Consumer
    participant MiniReact
    participant Reconciler
    participant ContextStack

    App->>MiniReact: render(<Provider value={...}><Consumer /></Provider>)
    MiniReact->>Reconciler: createVDOMInstance(Provider)
    Reconciler->>ContextStack: pushContext(contextId, value)
    Reconciler->>Reconciler: reconcile children (Consumer)
    Reconciler->>MiniReact: useContext(contextId)
    MiniReact->>ContextStack: getCurrentValue(contextId)
    Reconciler->>ContextStack: popContext()
    MiniReact->>App: render output with context value
Loading

Possibly related PRs

  • MarcelOlsen/mini-react#4: Updates phase descriptions in README for consistency—related due to overlap in roadmap/README changes, but this PR is way more comprehensive.

Poem

Context flows like water,
Through the MiniReact stream—
Providers and consumers,
Living the context dream.
The roadmap’s split, the scripts are tight,
Tests abound, the future’s bright!
Ship it, chat—this PR’s clean.

(∩`-´)⊃━☆゚.*・。゚ Context Magic!


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (6)
src/MiniReact.ts (1)

349-365: Leverage default on the context object itself

useContext recomputes the default via _defaultValue, ignoring the (possibly newer) _currentValue.
If you keep _currentValue, lean on it here; if not, delete both and stay single-source-of-truth.

src/types.ts (2)

94-108: ContextHook is unused – dead code is dead weight

I don’t see it referenced in the runtime. Yank it or wire it up so the type system actually earns its keep.


141-146: Two fields for one truth? Pick one 🔥

_currentValue vs _defaultValue – unless you’re updating _currentValue, this duality just confuses.
Simplify to a single defaultValue or keep them in sync.

README.md (3)

75-80: Next milestones look solid—use en dashes!
Love the clarity on Phases 9–11 and the v0.1.0 alpha goal. Quick nit: for time ranges, swap your hyphens for en dashes (2–3 weeks, 1–2 weeks) to level up typography.


82-82: Grammar nit: add “the”
Consider writing “the stable v1.0.0 release” for smoother reading.


685-695: Upgrade that test suite heading
That bold line for the comprehensive tests is screaming for a proper heading level and those trailing colons on “Test Categories” and “Running Tests” will trip Markdown lint. Swap to headings and drop the punctuation.

- **Comprehensive Test Suite: Unit and integration tests across 8 files**
+ ### Comprehensive Test Suite

- ### Test Categories:
+ ### Test Categories

- ### Running Tests:
+ ### Running Tests
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40a786f and bbc52de.

📒 Files selected for processing (6)
  • README.md (13 hunks)
  • package.json (1 hunks)
  • src/MiniReact.ts (6 hunks)
  • src/reconciler.ts (8 hunks)
  • src/types.ts (2 hunks)
  • tests/MiniReact.context.test.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/MiniReact.ts (2)
src/reconciler.ts (1)
  • setContextHooks (23-29)
src/types.ts (4)
  • MiniReactContext (141-146)
  • FunctionalComponent (9-11)
  • AnyMiniReactElement (7-7)
  • VDOMInstance (127-135)
🪛 markdownlint-cli2 (0.17.2)
README.md

15-15: Link fragments should be valid
null

(MD051, link-fragments)


20-20: Link fragments should be valid
null

(MD051, link-fragments)


21-21: Link fragments should be valid
null

(MD051, link-fragments)


24-24: Link fragments should be valid
null

(MD051, link-fragments)


25-25: Link fragments should be valid
null

(MD051, link-fragments)


26-26: Link fragments should be valid
null

(MD051, link-fragments)


27-27: Link fragments should be valid
null

(MD051, link-fragments)


28-28: Link fragments should be valid
null

(MD051, link-fragments)


32-32: Link fragments should be valid
null

(MD051, link-fragments)


38-38: Link fragments should be valid
null

(MD051, link-fragments)


685-685: Emphasis used instead of a heading
null

(MD036, no-emphasis-as-heading)


687-687: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


698-698: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🪛 LanguageTool
README.md

[typographical] ~80-~80: If specifying a range, consider using an en dash instead of a hyphen.
Context: ... 🎉 Alpha Release v0.1.0: Target in 4-6 weeks Post-Alpha Roadmap: 12 addit...

(HYPHEN_TO_EN)


[uncategorized] ~82-~82: You might be missing the article “the” here.
Context: ...map**: 12 additional phases planned for stable v1.0.0 release with advanced features i...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~418-~418: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority-based scheduling - High/low priority updates (similar to React's concurrent ...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[style] ~445-~445: This phrase is redundant (‘O’ stands for ‘optimization’). Use simply “SEO”.
Context: ...that work on both client and server - SEO optimization - Meta tag management and structured ...

(ACRONYM_TAUTOLOGY)

🔇 Additional comments (5)
package.json (1)

10-16: Scripts look clean, ship it 🚀

Nothing to nit on these biome shortcuts – they read well and do exactly what they say.
Keep crushing it.

tests/MiniReact.context.test.ts (1)

1-952: Legendary test coverage, chat!

This suite hammers every edge-case I could imagine. Absolute chef’s kiss.

README.md (3)

184-186: Effects & Context features – rock on!
Fantastic call including the Effects System and Context API in your Completed Features. This matches the code changes to the context system perfectly.


15-38: Alright, squad—our last script got bodied by sed’s brackets and a missing comm, so let’s drop a simpler, hard-hitting check:

#!/usr/bin/env bash
# 🔨 Extract all TOC link anchors
rg -oP '\(#\K[^)]+' README.md | sort > toc_links.txt

# 🔨 Extract all headings, normalize to GitHub-style slugs
rg '^#+ ' README.md \
  | sed -E 's/ *\[#.*\]//; s/[^a-zA-Z0-9 -]//g; s/ +/-/g; s/--+/-/g; s/^-+|-+$//g' \
  | tr '[:upper:]' '[:lower:]' \
  | sort > headings.txt

# 🔨 Show any anchors that don’t match real headings
grep -Fxv -f headings.txt toc_links.txt || echo "All anchors match headings 🎉"

63-73: Let’s suss out what test runner you’re packing in—gotta know how to call the suite, baby! 🔍✨

#!/usr/bin/env bash
# Peek the devDependencies to spot our test runner
jq '.devDependencies' package.json

Comment on lines +62 to +70
// Set the context hooks in the reconciler
setContextHooks(
(contextValues: Map<symbol, unknown>) => {
contextStack.push(contextValues);
},
() => {
contextStack.pop();
},
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Wrap push/pop in a try/finally, my dude 🔥

If any child reconciliation throws, we’ll leave the contextStack in a dirty state – doom-spiral for every render after that.
Guard the push with a try and guarantee the pop() in finally.

🤖 Prompt for AI Agents
In src/MiniReact.ts around lines 62 to 70, the contextStack push and pop
operations are not protected against exceptions during child reconciliation,
which can leave the stack in an inconsistent state. Wrap the push call in a try
block and ensure the pop call happens in a finally block to guarantee the stack
is cleaned up even if an error occurs during reconciliation.

@MarcelOlsen MarcelOlsen force-pushed the integration/context-system branch from bbc52de to 44905ee Compare June 17, 2025 12:10
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/reconciler.ts (2)

163-176: Context stack still left dangling – wrap push/pop in a try…finally, chat!

We’ve literally been here before: if the functional component blows up after pushContextFunction, popContextFunction never fires and your global context stack is yeeted into oblivion.
Same safety-net we pleaded for last round, still MIA. Slam a try around the child reconciliation and call pop… in the finally. EZ clap.

-		if (instance.contextValues && pushContextFunction) {
-			pushContextFunction(instance.contextValues);
-		}
-
-		const childInstance = childElement
-			? createVDOMInstance(parentDom, childElement)
-			: null;
-
-		// Pop context AFTER reconciling children
-		if (instance.contextValues && popContextFunction) {
-			popContextFunction();
-		}
+		let pushed = false;
+		if (instance.contextValues && pushContextFunction) {
+			pushContextFunction(instance.contextValues);
+			pushed = true;
+		}
+		let childInstance: VDOMInstance | null = null;
+		try {
+			childInstance = childElement
+				? createVDOMInstance(parentDom, childElement)
+				: null;
+		} finally {
+			if (pushed && popContextFunction) {
+				popContextFunction();
+			}
+		}

535-550: Déjà vu in updateVDOMInstance – still no finally, still risky

Copy-pasta the exact same push/pop pattern into updates without a guard? C’mon.
Wrap it or watch the context stack leak harder than my coffee at 3 AM.

Same diff pattern as above applies here.

README.md (1)

160-162: Context tests still AWOL in the quick-start – we talked about this

You added a 1 k-line context suite but the README still only shows the render test.
Give newcomers the one-liner so they can flex the new API.

 # Run specific test file
 bun test tests/MiniReact.render.test.ts
+# Run context tests
+bun test tests/MiniReact.context.test.ts
🧹 Nitpick comments (1)
tests/MiniReact.context.test.ts (1)

780-806: Triple-cast madness – ditch the as unknown as karaoke

(exposedSetContextValue as unknown as (value: …) => void) shows up all over.
That’s TypeScript screaming “help me”. Capture the setter with a properly typed ref instead of unsafe double-casting.

Example:

let setCtx!: (v: string | number | boolean) => void;

const App: FunctionalComponent = () => {
  const [ctx, setCtxFn] = useState<...>("initial");
  setCtx = setCtxFn;
  ...
};

Cleaner, safer, zero casts.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bbc52de and 44905ee.

📒 Files selected for processing (6)
  • README.md (13 hunks)
  • package.json (1 hunks)
  • src/MiniReact.ts (6 hunks)
  • src/reconciler.ts (8 hunks)
  • src/types.ts (2 hunks)
  • tests/MiniReact.context.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • package.json
  • src/types.ts
  • src/MiniReact.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/MiniReact.context.test.ts (1)
src/MiniReact.ts (3)
  • createContext (302-342)
  • useContext (349-365)
  • useState (157-217)
🪛 markdownlint-cli2 (0.17.2)
README.md

15-15: Link fragments should be valid
null

(MD051, link-fragments)


20-20: Link fragments should be valid
null

(MD051, link-fragments)


21-21: Link fragments should be valid
null

(MD051, link-fragments)


24-24: Link fragments should be valid
null

(MD051, link-fragments)


25-25: Link fragments should be valid
null

(MD051, link-fragments)


26-26: Link fragments should be valid
null

(MD051, link-fragments)


27-27: Link fragments should be valid
null

(MD051, link-fragments)


28-28: Link fragments should be valid
null

(MD051, link-fragments)


32-32: Link fragments should be valid
null

(MD051, link-fragments)


38-38: Link fragments should be valid
null

(MD051, link-fragments)


685-685: Emphasis used instead of a heading
null

(MD036, no-emphasis-as-heading)


687-687: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


698-698: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🪛 LanguageTool
README.md

[typographical] ~80-~80: If specifying a range, consider using an en dash instead of a hyphen.
Context: ... 🎉 Alpha Release v0.1.0: Target in 4-6 weeks Post-Alpha Roadmap: 12 addit...

(HYPHEN_TO_EN)


[uncategorized] ~82-~82: You might be missing the article “the” here.
Context: ...map**: 12 additional phases planned for stable v1.0.0 release with advanced features i...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~418-~418: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... - Priority-based scheduling - High/low priority updates (similar to React's concurrent ...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[style] ~445-~445: This phrase is redundant (‘O’ stands for ‘optimization’). Use simply “SEO”.
Context: ...that work on both client and server - SEO optimization - Meta tag management and structured ...

(ACRONYM_TAUTOLOGY)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
src/reconciler.ts (1)

420-436: We’re yeeting DOM nodes but ghost-leaving their hooks – memory leak alert 🟥

Left-over keyed / unkeyed children get their DOM brutally removeDomNode-d, but their effect hooks never see a cleanup pass, nor do their own children get traversed. The reconcile call you used at the top (reconcile(null, null, childInstance)) already does the full unmount dance (effect cleanup, recursive descent, eventSystem unregister, etc.).

Let’s use the same single source of truth instead of re-implementing (and partially forgetting) teardown logic.

-  // Remove any remaining old keyed children that weren't reused
-  for (const [, oldChild] of oldKeyed) {
-      if (oldChild.dom) {
-          eventSystem.unregisterInstance(oldChild);
-          removeDomNode(oldChild.dom);
-      }
-  }
+  // Unmount any remaining keyed children
+  for (const [, oldChild] of oldKeyed) {
+      reconcile(null, null, oldChild);   // full teardown incl. hooks
+  }
 
-  // Remove any remaining old unkeyed children that weren't reused
-  for (let i = unkeyedIndex; i < oldUnkeyed.length; i++) {
-      const oldChild = oldUnkeyed[i];
-      if (oldChild.dom) {
-          eventSystem.unregisterInstance(oldChild);
-          removeDomNode(oldChild.dom);
-      }
-  }
+  // …and the unkeyed stragglers
+  for (let i = unkeyedIndex; i < oldUnkeyed.length; i++) {
+      reconcile(null, null, oldUnkeyed[i]);
+  }

Without this, every un-reused subtree keeps its effects and memory around forever. Not pog.

🧹 Nitpick comments (3)
src/reconciler.ts (3)

548-560: DRY it up – push/try/finally/pop pattern is copy-pasted

You duplicated the exact same push-context / try / finally / pop sequence in both createVDOMInstance and updateVDOMInstance. Extract a tiny helper (e.g. withProviderContext(instance, fn)) so we can’t accidentally drift later. Makes the reconciler easier to scan at 3 AM.


233-234: Prettier is screaming – kill the stray spaces

Pipeline failed because of the extra space inside the empty block.

-let setCurrentRenderInstance: (instance: VDOMInstance | null) => void = () => { };
+let setCurrentRenderInstance: (instance: VDOMInstance | null) => void = () => {};

One tiny tweak, CI goes green.


550-554: Multiline call vs Prettier – single-liner wins

Prettier failure #2. Inline the call, no readability lost:

-childInstance = reconcile(
-    parentNode,
-    childElement,
-    oldChildInstance,
-);
+childInstance = reconcile(parentNode, childElement, oldChildInstance);

Ship it.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44905ee and 37fa397.

📒 Files selected for processing (3)
  • src/MiniReact.ts (7 hunks)
  • src/reconciler.ts (9 hunks)
  • tests/MiniReact.context.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/MiniReact.ts
🧰 Additional context used
🪛 GitHub Actions: CI
src/reconciler.ts

[error] 234-234: Prettier formatting check failed. Formatter would have changed 'let setCurrentRenderInstance: (instance: VDOMInstance | null) => void = () => { };' spacing.


[error] 550-554: Prettier formatting check failed. Formatter would have replaced multiline reconcile call with a single line call: 'childInstance = reconcile(parentNode, childElement, oldChildInstance);'.

🔇 Additional comments (1)
tests/MiniReact.context.test.ts (1)

26-34: Tests poke internals – future refactor foot-gun

_defaultValue, _currentValue, _contextId are undocumented internals. If the implementation ever makes them #private or moves them behind Symbols, these tests will blow up even though public behaviour is fine. Consider asserting through the public API only (render + read), or expose a sanctioned getCurrentValue() helper for test envs.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/reconciler.ts (1)

491-498: 🫡 Same leak pattern in the update path – slap that finally on!

The update branch repeats the push / call / pop sequence with no
exception-safety. Copy the pattern from the creation path to keep the render
stack pure.

🧹 Nitpick comments (1)
src/reconciler.ts (1)

310-333: 📚 Docstring vs. signature drift in diffProps

The JSDoc lists an instance param that the function no longer accepts.
Small but confusing – yank the stale mention or pass the param.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37fa397 and 929c955.

📒 Files selected for processing (2)
  • src/MiniReact.ts (6 hunks)
  • src/reconciler.ts (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/MiniReact.ts

Comment on lines +501 to +512
// Find the correct parent node to reconcile in
let parentNode: Node | null = null;
if (oldChildInstance?.dom?.parentNode) {
parentNode = oldChildInstance.dom.parentNode;
} else if (instance.dom?.parentNode) {
parentNode = instance.dom.parentNode;
}

if (!parentNode) {
throw new Error(
"Unable to find parent node for functional component reconciliation",
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🤔 “Unable to find parent node” when prev render returned null

parentNode is resolved only from oldChildInstance.dom or instance.dom.
Scenario: component previously rendered null, now returns a tree ⇒ both DOM
refs are null ⇒ we throw.
Walk up via instance.parent (or accept parentDom as a param) before
bailing.

-  if (!parentNode) {
-    throw new Error(
-      "Unable to find parent node for functional component reconciliation",
-    );
-  }
+  if (!parentNode) {
+    // fallback: climb until we hit a host node
+    let p: VDOMInstance | undefined = instance.parent;
+    while (p && !parentNode) {
+      parentNode = p.dom ?? null;
+      p = p.parent;
+    }
+    if (!parentNode) {
+      throw new Error(
+        "Unable to find parent node for functional component reconciliation",
+      );
+    }
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Find the correct parent node to reconcile in
let parentNode: Node | null = null;
if (oldChildInstance?.dom?.parentNode) {
parentNode = oldChildInstance.dom.parentNode;
} else if (instance.dom?.parentNode) {
parentNode = instance.dom.parentNode;
}
if (!parentNode) {
throw new Error(
"Unable to find parent node for functional component reconciliation",
);
// Find the correct parent node to reconcile in
let parentNode: Node | null = null;
if (oldChildInstance?.dom?.parentNode) {
parentNode = oldChildInstance.dom.parentNode;
} else if (instance.dom?.parentNode) {
parentNode = instance.dom.parentNode;
}
if (!parentNode) {
// fallback: climb until we hit a host node
let p: VDOMInstance | undefined = instance.parent;
while (p && !parentNode) {
parentNode = p.dom ?? null;
p = p.parent;
}
if (!parentNode) {
throw new Error(
"Unable to find parent node for functional component reconciliation",
);
}
}
🤖 Prompt for AI Agents
In src/reconciler.ts around lines 501 to 512, the code only checks
oldChildInstance.dom.parentNode and instance.dom.parentNode to find the parent
node, which fails if the previous render returned null and both DOM references
are null. To fix this, extend the logic to walk up the component tree using
instance.parent to find a valid parent DOM node before throwing an error.
Alternatively, consider accepting a parentDom parameter to use as a fallback
parent node.

@MarcelOlsen MarcelOlsen force-pushed the integration/context-system branch from d832d81 to c6600ee Compare June 17, 2025 13:06
MarcelOlsen and others added 2 commits June 17, 2025 15:08
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@MarcelOlsen MarcelOlsen merged commit 68c6c4f into master Jun 17, 2025
3 checks passed
@MarcelOlsen MarcelOlsen deleted the integration/context-system branch June 17, 2025 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant