Skip to content

Conversation

@andycall
Copy link
Member

@andycall andycall commented Dec 15, 2025

Based on #698

Summary:

  • Keep IntersectionObserver alive while observing (GC/reliability).
  • Implement additional IntersectionObserver/Entry fields (root/rootMargin/thresholds/takeRecords + rect/time).
  • Add IntersectionObserver v2 surface: scrollMargin/delay/trackVisibility + IntersectionObserverEntry.isVisible (isVisible currently mirrors isIntersecting when trackVisibility is enabled).
  • Add integration specs under integration_tests/specs/dom/intersection-observer.ts.

Summary by CodeRabbit

  • New Features

    • Full IntersectionObserver support: observe/unobserve/disconnect/takeRecords, thresholds, root/rootMargin/scrollMargin, delay, trackVisibility, and delivery of intersection entries to JS.
  • Bug Fixes

    • Added null-check to prevent crashes during native method invocation.
    • Made CPU detection for parallel builds robust.
  • Tests

    • Added comprehensive integration tests covering IntersectionObserver behavior and edge cases.
  • Chores

    • Stopped forcing CSS Grid enablement at startup.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 15, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
use-case Ready Ready Preview, Comment Dec 15, 2025 5:48am
@coderabbitai
Copy link

coderabbitai bot commented Dec 15, 2025

Walkthrough

Adds full IntersectionObserver support across native C++ bridge, QuickJS bindings, Dart bindings/FFI, rendering/event plumbing, UI command wiring, TypeScript declarations, and integration tests to enable observing element visibility and delivering entries to JS.

Changes

Cohort / File(s) Summary
C++ Core: IntersectionObserver types
bridge/core/dom/intersection_observer.h, bridge/core/dom/intersection_observer.cc, bridge/core/dom/intersection_observer_entry.h, bridge/core/dom/intersection_observer_entry.cc
New IntersectionObserver and IntersectionObserverEntry implementations: factories, constructors, observe/unobserve/disconnect, takeRecords, GC Trace integration, thresholds/delay/trackVisibility state, and native-to-JS callback marshalling.
C++ DOM integration
bridge/core/dom/document.h, bridge/core/dom/document.cc
Document registration/unregistration for observers; Document::Trace now traces registered observers; private container for observer Members.
QuickJS bindings & wrapper IDs
bridge/bindings/qjs/binding_initializer.cc, bridge/bindings/qjs/generated_code_helper.h, bridge/bindings/qjs/wrapper_type_info.h
Install QJSIntersectionObserver and QJSIntersectionObserverEntry bindings; add includes and two new JS class ID enum values.
Bridge build & templates
bridge/bridge_sources.json5, bridge/scripts/code_generator/templates/idl_templates/base.cc.tpl, bridge/scripts/code_generator/templates/idl_templates/dictionary.h.tpl, bridge/CMakeLists.txt
Add intersection_observer source files to build lists; include header in codegen template; add Node forward declaration in template; minor CMake whitespace edits.
Binding object & UI command infra (C++)
bridge/core/binding_object.h, bridge/core/binding_object.cc, bridge/foundation/ui_command_buffer.h, bridge/foundation/ui_command_buffer.cc, bridge/foundation/ui_command_strategy.cc
Add CreateBindingObjectType::kCreateIntersectionObserver; null-check native_method in HandleCallFromDartSide; introduce UICommandKind::kIntersectionObserver and three UICommand variants mapped to it; record handling added to strategy.
TypeScript declarations
bridge/core/dom/intersection_observer.d.ts, bridge/core/dom/intersection_observer_entry.d.ts, bridge/core/dom/intersection_observer_init.d.ts
Add interfaces for IntersectionObserver, IntersectionObserverEntry, and IntersectionObserverInit (constructors, properties, methods).
Dart bridge & UI command (Dart)
webf/lib/src/bridge/binding_bridge.dart, webf/lib/src/bridge/to_native.dart, webf/lib/src/bridge/ui_command.dart
Add CreateBindingObjectType.createIntersectionObserver; add UICommandType entries for add/remove/disconnect; exec handlers call view methods to manage native observers.
Dart DOM & delivery implementation
webf/lib/src/dom/intersection_observer.dart, webf/lib/src/dom/intersection_observer_entry.dart, webf/lib/src/dom/document.dart, webf/lib/src/dom/element.dart
Dart-side IntersectionObserver class, FFI structs for entries, entry accumulation/delivery via FFI, document/element lifecycle methods to add/remove/disconnect observers and collect/deliver pending records.
Rendering & event plumbing (Dart)
webf/lib/src/rendering/intersection_observer.dart, webf/lib/src/css/render_style.dart, webf/lib/src/dom/event.dart, webf/lib/src/html/img.dart
Change IntersectionChangeCallback signature to return bool; add threshold-aware dispatch, throttling, listener management, and RenderStyle listener hooks; adapt event handlers and img intersection handler to new signature.
View controller & per-frame delivery (Dart)
webf/lib/src/launcher/view_controller.dart, webf/lib/src/launcher/controller.dart
Add methods to add/remove/disconnect observers and deliver entries; integrate per-frame deliverIntersectionObserver into flushPendingCommandsPerFrame.
Tests & utilities
integration_tests/specs/dom/intersection-observer.ts, integration_tests/lib/main.dart, scripts/tasks.js, bridge/core/executing_context.cc
Add comprehensive intersection-observer integration tests; remove DebugFlags.enableCssGridLayout assignment; make CPU count robust; add include for intersection_observer.h.

Sequence Diagram

sequenceDiagram participant JS as JS participant QJS as QuickJS bridge participant Native as Native C++ participant Dart as Dart binding participant Doc as Document participant Elem as Element participant Render as RenderBoxModel JS->>QJS: new IntersectionObserver(callback, options) QJS->>Native: Create(context, function, init) Native->>Doc: RegisterIntersectionObserver(observer) Doc->>Doc: store observer JS->>QJS: observer.observe(element) QJS->>Native: observe(element) Native->>Dart: notify observation start Dart->>Elem: addIntersectionObserver(observer, thresholds) Elem->>Render: addIntersectionChangeListener(callback, thresholds) Note over Render: during layout/scroll Render->>Render: compute intersectionRatio Render->>Elem: _handleIntersectionObserver(entry) Elem->>Dart: addEntry(entry) Note over Dart: per-frame delivery Dart->>Dart: deliverIntersectionObserver() Dart->>Native: FFI call with native entry array Native->>Native: create IntersectionObserverEntry array Native->>QJS: convert to JS objects QJS->>JS: invoke callback(entries) 
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Mixed, cross-layer changes (C++ bridge, QuickJS, Dart FFI, rendering, tests).
  • Areas needing careful review:
    • bridge/core/dom/intersection_observer.cc — lifecycle, thresholds normalization, memory management.
    • webf/lib/src/dom/intersection_observer.dart — FFI allocation/cleanup and async delivery callback.
    • webf/lib/src/rendering/intersection_observer.dart — threshold logic, scheduling/timer changes.
    • Integration points: Document/Element registration, UI command mapping, and GC Trace correctness.

Possibly related PRs

Poem

🐰 I peek from burrow, keen and bright,
Watching boxes dance in light,
Thresholds crossed and records stored,
Tiny hops deliver toward—
Callbacks ring, observers cheer! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.41% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(dom): complete IntersectionObserver API' accurately reflects the main objective of this PR, which is to implement a comprehensive IntersectionObserver API with lifecycle management, additional fields, and v2 features.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add_intersection_observer_new

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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: 15

🧹 Nitpick comments (11)
scripts/tasks.js (1)

111-111: Apply the same defensive CPU counting pattern here for consistency.

Line 111 uses os.cpus().length directly without guards, which could fail in the same scenarios that line 171 addresses. Line 570 in the configureAndBuildIOSTarget function has the same issue.

Apply this diff at line 111:

- let cpus = os.cpus(); - execSync(`cmake --build ${paths.bridge}/cmake-build-macos-${currentArch} --target ${webfTargets.join(' ')} -- -j ${cpus.length}`, { + const cpuCount = Math.max(1, (os.cpus() || []).length || 1); + execSync(`cmake --build ${paths.bridge}/cmake-build-macos-${currentArch} --target ${webfTargets.join(' ')} -- -j ${cpuCount}`, {

Apply this diff at line 570 in the configureAndBuildIOSTarget function:

- const cpuCount = os.cpus().length; + const cpuCount = Math.max(1, (os.cpus() || []).length || 1);
webf/lib/src/rendering/intersection_observer.dart (1)

202-214: IntersectionObserverLayer timer and callback throttling: minor cleanup opportunities

  • _timer is static and never cancelled; it continues firing even when _updated is empty. While _processCallbacks exits quickly in that case, this still keeps a periodic timer alive for the lifetime of the process. Consider cancelling the timer when there are no more active layers and reinstating it on demand.
  • _handleUpdateTimer() is now unused since _scheduleIntersectionObservationUpdate() creates its own Timer.periodic with an inline callback. This dead code can be removed for clarity.

These are non‑blocking but would simplify the lifecycle and reduce background work slightly.

Also applies to: 269-281, 303-326, 371-381, 389-424

bridge/core/binding_object.h (1)

75-81: Ensure CreateBindingObjectType stays in sync across C++ and Dart

Adding kCreateIntersectionObserver = 4 is fine here, but all call‑sites (e.g., the Dart FFI side and any C++ switch statements) must be updated to use this new enum value consistently to avoid mis‑dispatch.

Please double‑check that every switch/dispatch over CreateBindingObjectType (including the Dart bridge enum) has a corresponding kCreateIntersectionObserver / createIntersectionObserver case wired up.

integration_tests/specs/dom/intersection-observer.ts (1)

31-435: Comprehensive test coverage, but missing cleanup.

The test suite covers the IntersectionObserver API surface thoroughly, including v2 features. However, tests don't clean up created DOM elements after execution, which could cause test pollution. Per coding guidelines, created elements should be removed after tests.

Consider adding an afterEach block to clean up:

afterEach(() => { // Reset scroll position window.scrollTo(0, 0); // Remove test elements (spacers and observed elements) document.body.innerHTML = ''; });

Alternatively, wrap test-specific cleanup in each test or use a shared cleanup utility.

bridge/core/dom/intersection_observer.d.ts (1)

14-15: Consider the static analysis warning about new in interface.

Biome flags new(callback: Function, options?: IntersectionObserverInit): IntersectionObserver as misleading since interfaces aren't directly instantiable. However, reviewing IntersectionObserverEntry.d.ts shows this is a project convention for WebF bridge bindings code generation.

If this pattern is intentional for the code generator, consider adding a Biome ignore directive or documenting this convention. Otherwise, a class declaration with a constructor might be more semantically accurate.

webf/lib/src/dom/element.dart (1)

1157-1158: Consider clearing _intersectionObserverList in dispose for completeness.

While observers should ideally disconnect before element disposal, explicitly clearing the observer set in dispose() would ensure no stale references remain and provide defense-in-depth cleanup.

 renderStyle.removeIntersectionChangeListener(_handleIntersectionObserver); + _intersectionObserverList.clear(); super.dispose();
webf/lib/src/dom/intersection_observer.dart (2)

117-126: Unnecessary null assertion operator on element.

At line 123, element! uses a null assertion, but _elementList is declared as List<Element> (line 219), not List<Element?>. The null assertion is unnecessary and could mask type errors if the list type changes.

 for (var element in _elementList) { - element!.removeIntersectionObserver(this); + element.removeIntersectionObserver(this); }

128-130: Method naming violates Dart conventions.

HasObservations() uses PascalCase, but Dart conventions (and the coding guidelines) require camelCase for methods and functions.

- bool HasObservations() { + bool hasObservations() { return _elementList.isNotEmpty; }

As per coding guidelines: "Variables and functions must use camelCase in Dart".

bridge/core/dom/intersection_observer_entry.h (1)

7-8: Header guard path doesn't match actual file location.

The header guard suggests a path of core/intersection_observer/intersection_observer_entry.h but the file is actually at core/dom/intersection_observer_entry.h. While this doesn't affect functionality, it could cause confusion.

-#ifndef WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_ENTRY_H_ -#define WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_ENTRY_H_ +#ifndef WEBF_CORE_DOM_INTERSECTION_OBSERVER_ENTRY_H_ +#define WEBF_CORE_DOM_INTERSECTION_OBSERVER_ENTRY_H_ ... -#endif // WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_ENTRY_H_ +#endif // WEBF_CORE_DOM_INTERSECTION_OBSERVER_ENTRY_H_
bridge/core/dom/intersection_observer.h (1)

7-8: Header guard path doesn't match actual file location.

Same issue as the entry header - the guard suggests core/intersection_observer/ but the file is in core/dom/.

-#ifndef WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_H_ -#define WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_H_ +#ifndef WEBF_CORE_DOM_INTERSECTION_OBSERVER_H_ +#define WEBF_CORE_DOM_INTERSECTION_OBSERVER_H_ ... -#endif // WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_H_ +#endif // WEBF_CORE_DOM_INTERSECTION_OBSERVER_H_
bridge/core/dom/intersection_observer.cc (1)

48-94: Consider simplifying repeated null checks.

The constructor has many repeated observer_init && checks. While functionally correct, this could be simplified for better readability.

Consider this refactoring:

 IntersectionObserver::IntersectionObserver(ExecutingContext* context, const std::shared_ptr<QJSFunction>& function, const std::shared_ptr<IntersectionObserverInit>& observer_init) : BindingObject(context->ctx()), function_(function) { - if (observer_init && observer_init->hasRoot()) { - root_ = observer_init->root(); - } - if (observer_init && observer_init->hasRootMargin()) { - root_margin_ = observer_init->rootMargin(); - } - if (observer_init && observer_init->hasScrollMargin()) { - scroll_margin_ = observer_init->scrollMargin(); - } - if (observer_init && observer_init->hasDelay()) { - delay_ = std::max(0.0, observer_init->delay()); - } - if (observer_init && observer_init->hasTrackVisibility()) { - track_visibility_ = observer_init->trackVisibility(); + if (observer_init) { + if (observer_init->hasRoot()) { + root_ = observer_init->root(); + } + if (observer_init->hasRootMargin()) { + root_margin_ = observer_init->rootMargin(); + } + if (observer_init->hasScrollMargin()) { + scroll_margin_ = observer_init->scrollMargin(); + } + if (observer_init->hasDelay()) { + delay_ = std::max(0.0, observer_init->delay()); + } + if (observer_init->hasTrackVisibility()) { + track_visibility_ = observer_init->trackVisibility(); + } }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd2bc14 and 46a1bfd.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (38)
  • bridge/CMakeLists.txt (2 hunks)
  • bridge/bindings/qjs/binding_initializer.cc (2 hunks)
  • bridge/bindings/qjs/generated_code_helper.h (1 hunks)
  • bridge/bindings/qjs/wrapper_type_info.h (1 hunks)
  • bridge/bridge_sources.json5 (2 hunks)
  • bridge/core/binding_object.cc (1 hunks)
  • bridge/core/binding_object.h (1 hunks)
  • bridge/core/dom/document.cc (2 hunks)
  • bridge/core/dom/document.h (4 hunks)
  • bridge/core/dom/intersection_observer.cc (1 hunks)
  • bridge/core/dom/intersection_observer.d.ts (1 hunks)
  • bridge/core/dom/intersection_observer.h (1 hunks)
  • bridge/core/dom/intersection_observer_entry.cc (1 hunks)
  • bridge/core/dom/intersection_observer_entry.d.ts (1 hunks)
  • bridge/core/dom/intersection_observer_entry.h (1 hunks)
  • bridge/core/dom/intersection_observer_init.d.ts (1 hunks)
  • bridge/core/executing_context.cc (1 hunks)
  • bridge/foundation/ui_command_buffer.cc (1 hunks)
  • bridge/foundation/ui_command_buffer.h (2 hunks)
  • bridge/foundation/ui_command_strategy.cc (1 hunks)
  • bridge/scripts/code_generator/templates/idl_templates/base.cc.tpl (1 hunks)
  • bridge/scripts/code_generator/templates/idl_templates/dictionary.h.tpl (1 hunks)
  • integration_tests/lib/main.dart (0 hunks)
  • integration_tests/specs/dom/intersection-observer.ts (1 hunks)
  • scripts/tasks.js (1 hunks)
  • webf/lib/src/bridge/binding_bridge.dart (3 hunks)
  • webf/lib/src/bridge/to_native.dart (1 hunks)
  • webf/lib/src/bridge/ui_command.dart (1 hunks)
  • webf/lib/src/css/render_style.dart (1 hunks)
  • webf/lib/src/dom/document.dart (4 hunks)
  • webf/lib/src/dom/element.dart (5 hunks)
  • webf/lib/src/dom/event.dart (1 hunks)
  • webf/lib/src/dom/intersection_observer.dart (1 hunks)
  • webf/lib/src/dom/intersection_observer_entry.dart (1 hunks)
  • webf/lib/src/html/img.dart (2 hunks)
  • webf/lib/src/launcher/controller.dart (1 hunks)
  • webf/lib/src/launcher/view_controller.dart (3 hunks)
  • webf/lib/src/rendering/intersection_observer.dart (11 hunks)
💤 Files with no reviewable changes (1)
  • integration_tests/lib/main.dart
🧰 Additional context used
📓 Path-based instructions (11)
scripts/**/tasks.js

📄 CodeRabbit inference engine (scripts/CLAUDE.md)

scripts/**/tasks.js: Add global declarations for document and window in the merge-bridge-typings task defined in tasks.js
Display task-level errors in type generation with specific error messages, build tool output, and parsing errors including file paths and line numbers

Files:

  • scripts/tasks.js
scripts/**/*.{js,json}

📄 CodeRabbit inference engine (CLAUDE.md)

scripts/**/*.{js,json}: Bundle QuickJS into the WebF library for Android builds by default using static STL
Use separate QuickJS library only in advanced scenarios when sharing QuickJS with other libraries
Set ANDROID_STL=c++_static as the default C++ standard library for Android builds

Files:

  • scripts/tasks.js
bridge/**/*.{cc,cpp,h,hpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{cc,cpp,h,hpp}: C++ code should follow Chromium style (.clang-format) with C++17 standard, 120 character column limit, and 2-space indentation
Use WEBF_EXPORT_C macro for exporting C functions to Dart FFI
In FFI contexts, use Dart_Handle instead of Handle for type compatibility
For C++ FFI function naming: use GetObjectPropertiesFromDart for C++ exports, NativeGetObjectPropertiesFunc for Dart typedefs, and GetObjectPropertiesFunc for Dart functions
Lambda signatures in C++ must match expected function signatures to avoid FFI type mismatches
Choose power-of-2 buffer sizes (512, 1024, 2048) for ring buffer implementation, with smaller sizes for DEBUG_BUILD, MOBILE constraints, and larger sizes for DESKTOP performance

Files:

  • bridge/core/binding_object.cc
  • bridge/core/executing_context.cc
  • bridge/bindings/qjs/generated_code_helper.h
  • bridge/core/dom/document.h
  • bridge/bindings/qjs/wrapper_type_info.h
  • bridge/core/dom/intersection_observer_entry.cc
  • bridge/bindings/qjs/binding_initializer.cc
  • bridge/foundation/ui_command_strategy.cc
  • bridge/foundation/ui_command_buffer.cc
  • bridge/core/binding_object.h
  • bridge/foundation/ui_command_buffer.h
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/document.cc
  • bridge/core/dom/intersection_observer_entry.h
  • bridge/core/dom/intersection_observer.h
bridge/**/*.{cc,cpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{cc,cpp}: For async FFI operations, use Dart_NewPersistentHandle_DL to keep Dart objects alive, convert back with Dart_HandleFromPersistent_DL before use, and always call Dart_DeletePersistentHandle_DL after the async operation completes
For string handling in FFI, copy strings that might be freed using std::string(const_char_ptr), and use toNativeUtf8() with proper memory deallocation
For async callbacks with potential errors, always provide error path in callbacks (e.g., callback(object, nullptr)), handle cancellation cases in async operations, and propagate errors through callback parameters rather than exceptions
For thread-safe error reporting in FFI, copy error messages before crossing thread boundaries using std::string to ensure string lifetime, and consider error callbacks separate from result callbacks
Avoid PostToJsSync when threads may interdepend to prevent synchronous deadlocks in FFI communication
Ensure callback functions aren't invoked after context destruction to prevent use-after-free errors in FFI async operations
Implement ring buffer overflow handling with metrics and alerts to monitor command buffer capacity
Process multiple UI commands per frame in a loop with a MAX_COMMANDS_PER_FRAME limit to balance responsiveness and performance
Pin threads to cores for optimal cache usage in ring buffer operations by setting CPU affinity for UI threads
Use PostToJs for executing operations on the JS thread from other threads, PostToDart for returning results to Dart isolate, and avoid PostToJsSync to prevent deadlocks

Files:

  • bridge/core/binding_object.cc
  • bridge/core/executing_context.cc
  • bridge/core/dom/intersection_observer_entry.cc
  • bridge/bindings/qjs/binding_initializer.cc
  • bridge/foundation/ui_command_strategy.cc
  • bridge/foundation/ui_command_buffer.cc
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/document.cc
bridge/**/*.{cc,h}

📄 CodeRabbit inference engine (AGENTS.md)

C++ code in bridge module must use C++17 standard with 2-space indentation, 120 column limit, and follow Chromium style guide as defined in .clang-format

bridge/**/*.{cc,h}: Use RAII patterns in C++ where possible for resource management
Use PostToJs for executing operations on the JS thread in FFI
Use PostToDart for returning results to Dart isolate
Avoid PostToJsSync synchronous execution when possible

Files:

  • bridge/core/binding_object.cc
  • bridge/core/executing_context.cc
  • bridge/bindings/qjs/generated_code_helper.h
  • bridge/core/dom/document.h
  • bridge/bindings/qjs/wrapper_type_info.h
  • bridge/core/dom/intersection_observer_entry.cc
  • bridge/bindings/qjs/binding_initializer.cc
  • bridge/foundation/ui_command_strategy.cc
  • bridge/foundation/ui_command_buffer.cc
  • bridge/core/binding_object.h
  • bridge/foundation/ui_command_buffer.h
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/document.cc
  • bridge/core/dom/intersection_observer_entry.h
  • bridge/core/dom/intersection_observer.h
{bridge/**/*.{cc,h},webf/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

Document memory ownership clearly in FFI implementations

Files:

  • bridge/core/binding_object.cc
  • bridge/core/executing_context.cc
  • bridge/bindings/qjs/generated_code_helper.h
  • webf/lib/src/launcher/controller.dart
  • bridge/core/dom/document.h
  • bridge/bindings/qjs/wrapper_type_info.h
  • webf/lib/src/bridge/ui_command.dart
  • webf/lib/src/bridge/to_native.dart
  • bridge/core/dom/intersection_observer_entry.cc
  • bridge/bindings/qjs/binding_initializer.cc
  • bridge/foundation/ui_command_strategy.cc
  • webf/lib/src/dom/document.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • bridge/foundation/ui_command_buffer.cc
  • webf/lib/src/html/img.dart
  • webf/lib/src/dom/event.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • webf/lib/src/css/render_style.dart
  • bridge/core/binding_object.h
  • bridge/foundation/ui_command_buffer.h
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/document.cc
  • webf/lib/src/rendering/intersection_observer.dart
  • bridge/core/dom/intersection_observer_entry.h
  • bridge/core/dom/intersection_observer.h
bridge/**/*.{h,hpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{h,hpp}: Ring buffer command structure should use enum Type : uint8_t for command types with union for type-specific data to ensure type-safe and cache-friendly command handling
Ring buffer implementation should use alignas(64) for atomic head and tail pointers, std::atomic<size_t> for thread-safe synchronization, and power-of-2 buffer sizes enforced with static_assert

Files:

  • bridge/bindings/qjs/generated_code_helper.h
  • bridge/core/dom/document.h
  • bridge/bindings/qjs/wrapper_type_info.h
  • bridge/core/binding_object.h
  • bridge/foundation/ui_command_buffer.h
  • bridge/core/dom/intersection_observer_entry.h
  • bridge/core/dom/intersection_observer.h
integration_tests/specs/**/*.ts

📄 CodeRabbit inference engine (integration_tests/CLAUDE.md)

integration_tests/specs/**/*.ts: Place tests in appropriate directories under specs/ (css/, dom/, or window/)
Use TypeScript (.ts extension) for test files
Use done() callback for async tests
Use snapshot() for visual regression tests to capture current rendering
Use simulateClick with coordinates for hit testing tests
Test assets should reference files in assets/ directory
Use fdescribe() instead of describe() to run only specific test specs (Jasmine feature)
Use fit() instead of it() to run only specific test cases
Snapshots are stored as images for comparison and failed snapshots generate diff images
The max width of testing window is 340px
Test specs will always pass if there are no existing snapshots
Group related tests in describe blocks
Each test should be independent
Remove created elements after tests (test cleanup)
Use clear, descriptive test names
Test behavior, not implementation
Include edge cases and error conditions in tests
Batch DOM operations to minimize reflows
Use async/await and proper async patterns for asynchronous operations in tests
Measure operations using performance.now() for timing in performance-critical tests

Files:

  • integration_tests/specs/dom/intersection-observer.ts
webf/**/*.dart

📄 CodeRabbit inference engine (webf/CLAUDE.md)

webf/**/*.dart: Follow rules in webf/analysis_options.yaml for Dart code style
Use single quotes for strings in Dart code
File names must use snake_case in Dart
Class names must use PascalCase in Dart
Variables and functions must use camelCase in Dart
Prefer final fields when applicable in Dart code
Lines should be max 120 characters in Dart code
Always free allocated memory in Dart FFI using malloc.free() for toNativeUtf8() allocations
Free FFI allocated memory in finally blocks to ensure cleanup on exceptions
Track ownership of allocated pointers in FFI callbacks
Free NativeValue pointers after converting with fromNativeValue in FFI code
Document memory ownership clearly in FFI async callbacks
Implement WidgetElement to create custom Flutter widgets integrated into WebF's DOM tree
Register custom WidgetElements using WidgetElementRegistry.register(tagName, builder)
Override buildWidget(BuildContext context) method in WidgetElement to build the Flutter widget
Call updateWidget() when attributes change in WidgetElement implementations
Dispose controllers and subscriptions in WidgetElement for memory management
Follow W3C event standards when dispatching events from WidgetElement
Minimize widget rebuilds in WidgetElement for performance optimization
Implement ARIA attributes in WidgetElement when applicable for accessibility

Dart code in webf module must follow naming conventions: snake_case for file names, PascalCase for classes, and camelCase for class members

webf/**/*.dart: Always free allocated memory in Dart FFI
Use malloc.free() for toNativeUtf8() allocations in Dart FFI
Track pointer ownership in callbacks within Dart FFI

Files:

  • webf/lib/src/launcher/controller.dart
  • webf/lib/src/bridge/ui_command.dart
  • webf/lib/src/bridge/to_native.dart
  • webf/lib/src/dom/document.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/html/img.dart
  • webf/lib/src/dom/event.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • webf/lib/src/css/render_style.dart
  • webf/lib/src/rendering/intersection_observer.dart
webf/lib/src/css/**/*.dart

📄 CodeRabbit inference engine (webf/CLAUDE.md)

Use CSSRenderStyle for style computation and storage in Dart CSS code

Files:

  • webf/lib/src/css/render_style.dart
webf/lib/src/rendering/**/*.dart

📄 CodeRabbit inference engine (webf/CLAUDE.md)

Use RenderBoxModel as base class for layout in Dart rendering code

Files:

  • webf/lib/src/rendering/intersection_observer.dart
🧠 Learnings (60)
📓 Common learnings
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp} : Use PostToJs for executing operations on the JS thread from other threads, PostToDart for returning results to Dart isolate, and avoid PostToJsSync to prevent deadlocks 
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/**/tasks.js : Display task-level errors in type generation with specific error messages, build tool output, and parsing errors including file paths and line numbers 

Applied to files:

  • scripts/tasks.js
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/**/tasks.js : Add global declarations for `document` and `window` in the `merge-bridge-typings` task defined in `tasks.js` 

Applied to files:

  • scripts/tasks.js
📚 Learning: 2025-11-26T10:24:13.090Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: cli/CLAUDE.md:0-0 Timestamp: 2025-11-26T10:24:13.090Z Learning: Applies to cli/**/*.ts : Process files in batches using processFilesInBatch for optimal parallelism 

Applied to files:

  • scripts/tasks.js
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Build for macOS using `npm run build:bridge:macos` (debug) or `npm run build:bridge:macos:release` (release); for iOS use `npm run build:bridge:ios` (debug) or `npm run build:bridge:ios:release` (release); for Android use `npm run build:bridge:android` (debug) or `npm run build:bridge:android:release` (release) 

Applied to files:

  • scripts/tasks.js
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp,h,hpp} : For C++ FFI function naming: use `GetObjectPropertiesFromDart` for C++ exports, `NativeGetObjectPropertiesFunc` for Dart typedefs, and `GetObjectPropertiesFunc` for Dart functions 

Applied to files:

  • bridge/core/binding_object.cc
  • webf/lib/src/bridge/binding_bridge.dart
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/intersection_observer.h
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp,h,hpp} : In FFI contexts, use `Dart_Handle` instead of `Handle` for type compatibility 

Applied to files:

  • bridge/core/binding_object.cc
  • webf/lib/src/bridge/binding_bridge.dart
  • bridge/core/dom/intersection_observer.cc
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp} : For async FFI operations, use `Dart_NewPersistentHandle_DL` to keep Dart objects alive, convert back with `Dart_HandleFromPersistent_DL` before use, and always call `Dart_DeletePersistentHandle_DL` after the async operation completes 

Applied to files:

  • bridge/core/binding_object.cc
  • webf/lib/src/dom/intersection_observer.dart
  • bridge/core/dom/intersection_observer.cc
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Free NativeValue pointers after converting with fromNativeValue in FFI code 

Applied to files:

  • bridge/core/binding_object.cc
  • webf/lib/src/dom/intersection_observer_entry.dart
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to bridge/**/*.{cc,h} : Use `PostToDart` for returning results to Dart isolate 

Applied to files:

  • bridge/core/binding_object.cc
  • webf/lib/src/bridge/ui_command.dart
  • webf/lib/src/bridge/to_native.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • bridge/core/dom/intersection_observer.cc
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/lib/bridge.dart : lib/bridge.dart contains FFI bindings to C++ bridge 

Applied to files:

  • bridge/core/binding_object.cc
  • webf/lib/src/launcher/controller.dart
  • webf/lib/src/bridge/ui_command.dart
  • webf/lib/src/bridge/to_native.dart
  • webf/lib/src/dom/document.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • bridge/core/dom/intersection_observer.cc
  • webf/lib/src/rendering/intersection_observer.dart
  • bridge/core/dom/intersection_observer_entry.h
  • bridge/core/dom/intersection_observer.h
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to bridge/**/*.{cc,h} : Use `PostToJs` for executing operations on the JS thread in FFI 

Applied to files:

  • bridge/core/executing_context.cc
  • bridge/core/dom/document.h
  • bridge/bridge_sources.json5
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp} : Avoid `PostToJsSync` when threads may interdepend to prevent synchronous deadlocks in FFI communication 

Applied to files:

  • bridge/core/executing_context.cc
  • bridge/bindings/qjs/generated_code_helper.h
  • bridge/core/dom/document.h
  • bridge/bridge_sources.json5
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/bridge/polyfill/**/*.{ts,tsx,d.ts} : Include a reference to `webf.d.ts` in polyfill type generation for accessing core types like `EventTarget` 

Applied to files:

  • bridge/core/executing_context.cc
  • bridge/core/dom/intersection_observer_entry.d.ts
  • bridge/core/dom/intersection_observer.d.ts
  • bridge/core/dom/intersection_observer_init.d.ts
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to bridge/**/*.{cc,h} : Avoid `PostToJsSync` synchronous execution when possible 

Applied to files:

  • bridge/core/executing_context.cc
  • bridge/core/dom/document.h
  • bridge/bridge_sources.json5
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp} : Use PostToJs for executing operations on the JS thread from other threads, PostToDart for returning results to Dart isolate, and avoid PostToJsSync to prevent deadlocks 

Applied to files:

  • bridge/core/executing_context.cc
  • webf/lib/src/bridge/ui_command.dart
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/intersection_observer.h
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp,h,hpp} : Use `WEBF_EXPORT_C` macro for exporting C functions to Dart FFI 

Applied to files:

  • bridge/core/executing_context.cc
  • webf/lib/src/bridge/ui_command.dart
  • webf/lib/src/bridge/to_native.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • bridge/scripts/code_generator/templates/idl_templates/dictionary.h.tpl
  • webf/lib/src/dom/intersection_observer_entry.dart
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/intersection_observer.h
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to {bridge/**/*.{cc,h},webf/**/*.dart} : Document memory ownership clearly in FFI implementations 

Applied to files:

  • bridge/core/executing_context.cc
  • bridge/core/dom/document.h
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • bridge/core/dom/intersection_observer.cc
  • bridge/core/dom/document.cc
  • bridge/core/dom/intersection_observer.h
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Batch DOM operations to minimize reflows 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Test behavior, not implementation 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Place tests in appropriate directories under `specs/` (css/, dom/, or window/) 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Use `snapshot()` for visual regression tests to capture current rendering 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Use async/await and proper async patterns for asynchronous operations in tests 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Measure operations using `performance.now()` for timing in performance-critical tests 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Include edge cases and error conditions in tests 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Remove created elements after tests (test cleanup) 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Use clear, descriptive test names 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:27:27.888Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: integration_tests/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:27.888Z Learning: Applies to integration_tests/specs/**/*.ts : Each test should be independent 

Applied to files:

  • integration_tests/specs/dom/intersection-observer.ts
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: No build needed for Dart-only changes in webf/ 

Applied to files:

  • webf/lib/src/launcher/controller.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • webf/lib/src/rendering/intersection_observer.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/test/**/*_test.dart : Use mock bundles from test/src/foundation/mock_bundle.dart for testing in unit tests 

Applied to files:

  • webf/lib/src/launcher/controller.dart
  • webf/lib/src/launcher/view_controller.dart
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to webf/**/*.dart : Track pointer ownership in callbacks within Dart FFI 

Applied to files:

  • webf/lib/src/launcher/controller.dart
  • webf/lib/src/dom/document.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/html/img.dart
  • webf/lib/src/dom/event.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • bridge/core/dom/intersection_observer.cc
  • webf/lib/src/rendering/intersection_observer.dart
  • bridge/core/dom/intersection_observer_entry.h
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Implement WidgetElement to create custom Flutter widgets integrated into WebF's DOM tree 

Applied to files:

  • webf/lib/src/launcher/controller.dart
  • webf/lib/src/dom/document.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Document memory ownership clearly in FFI async callbacks 

Applied to files:

  • webf/lib/src/launcher/controller.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/html/img.dart
  • webf/lib/src/dom/event.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • webf/lib/src/rendering/intersection_observer.dart
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/bridge/core/**/*.d.ts : DO NOT manually edit `bridge/typings/webf.d.ts` - it is generated from bridge/core/*.d.ts 

Applied to files:

  • bridge/core/dom/intersection_observer_entry.d.ts
  • bridge/core/dom/intersection_observer.d.ts
  • bridge/core/dom/intersection_observer_init.d.ts
  • bridge/bridge_sources.json5
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/bridge/polyfill/**/*.{ts,tsx} : DO NOT manually edit `bridge/typings/polyfill.d.ts` - it is generated from polyfill TypeScript source 

Applied to files:

  • bridge/core/dom/intersection_observer_entry.d.ts
  • bridge/core/dom/intersection_observer_init.d.ts
  • bridge/bridge_sources.json5
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/bridge/typings/index.d.ts : Configure `bridge/typings/index.d.ts` to reference both `webf.d.ts` and `polyfill.d.ts` and re-export polyfill module exports for a unified interface 

Applied to files:

  • bridge/core/dom/intersection_observer_entry.d.ts
  • bridge/core/dom/intersection_observer_init.d.ts
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/bridge/core/**/*.d.ts : Transform WebF-specific type annotations: `DartImpl<T>` → `T`, `StaticMember<T>` → `T`, `StaticMethod<T>` → `T`, `SupportAsync<T>` → generates both sync and async variants, `DependentsOnLayout<T>` → `T` 

Applied to files:

  • webf/lib/src/bridge/ui_command.dart
  • webf/lib/src/bridge/to_native.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • webf/lib/src/rendering/intersection_observer.dart
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp} : Process multiple UI commands per frame in a loop with a MAX_COMMANDS_PER_FRAME limit to balance responsiveness and performance 

Applied to files:

  • webf/lib/src/bridge/ui_command.dart
  • bridge/foundation/ui_command_strategy.cc
  • bridge/foundation/ui_command_buffer.cc
  • bridge/foundation/ui_command_buffer.h
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/test/**/*_test.dart : Access render objects in tests to verify layout calculations 

Applied to files:

  • webf/lib/src/dom/document.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/lib/src/rendering/**/*.dart : Use RenderBoxModel as base class for layout in Dart rendering code 

Applied to files:

  • webf/lib/src/dom/document.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/css/render_style.dart
  • webf/lib/src/rendering/intersection_observer.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Minimize widget rebuilds in WidgetElement for performance optimization 

Applied to files:

  • webf/lib/src/dom/document.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/event.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/rendering/intersection_observer.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/lib/src/css/**/*.dart : Use CSSRenderStyle for style computation and storage in Dart CSS code 

Applied to files:

  • webf/lib/src/dom/document.dart
  • webf/lib/src/dom/element.dart
  • webf/lib/src/css/render_style.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/test/**/*_test.dart : Use WebFWidgetTestUtils.prepareWidgetTest() to test HTML/CSS rendering in widget unit tests 

Applied to files:

  • webf/lib/src/dom/document.dart
  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Use widget unit tests to verify rendering changes with: cd webf && flutter test test/src/rendering/ 

Applied to files:

  • webf/lib/src/dom/document.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Follow W3C event standards when dispatching events from WidgetElement 

Applied to files:

  • webf/lib/src/dom/document.dart
  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/dom/event.dart
  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Dispose controllers and subscriptions in WidgetElement for memory management 

Applied to files:

  • webf/lib/src/dom/document.dart
  • webf/lib/src/launcher/view_controller.dart
📚 Learning: 2025-12-08T23:27:41.357Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: scripts/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:41.357Z Learning: Applies to scripts/bridge/core/**/*.d.ts : Create a `webf` namespace containing all type exports from merged bridge core types 

Applied to files:

  • bridge/scripts/code_generator/templates/idl_templates/base.cc.tpl
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Track ownership of allocated pointers in FFI callbacks 

Applied to files:

  • webf/lib/src/bridge/binding_bridge.dart
  • webf/lib/src/launcher/view_controller.dart
  • webf/lib/src/dom/intersection_observer.dart
  • webf/lib/src/dom/intersection_observer_entry.dart
  • bridge/core/dom/intersection_observer.cc
  • webf/lib/src/rendering/intersection_observer.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Implement ARIA attributes in WidgetElement when applicable for accessibility 

Applied to files:

  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Call updateWidget() when attributes change in WidgetElement implementations 

Applied to files:

  • webf/lib/src/dom/element.dart
  • webf/lib/src/css/render_style.dart
  • webf/lib/src/rendering/intersection_observer.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Follow rules in webf/analysis_options.yaml for Dart code style 

Applied to files:

  • webf/lib/src/dom/element.dart
  • webf/lib/src/css/render_style.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Class names must use PascalCase in Dart 

Applied to files:

  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Use single quotes for strings in Dart code 

Applied to files:

  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/**/*.dart : Prefer final fields when applicable in Dart code 

Applied to files:

  • webf/lib/src/dom/element.dart
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/ios/webf_ios.podspec : Ensure all source files, particularly `member_installer.cc`, are included in the `source_files` pattern in `ios/webf_ios.podspec` 

Applied to files:

  • bridge/bridge_sources.json5
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/ios/webf_ios.podspec : Include all necessary C++ bridge source files with pattern `bridge/**/*.{h,cc,cpp}` and bindings with `bridge/bindings/**/*.{h,cc}` in the iOS podspec source_files 

Applied to files:

  • bridge/bridge_sources.json5
📚 Learning: 2025-12-08T23:28:11.651Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-08T23:28:11.651Z Learning: Applies to bridge/**/*.{cc,h} : C++ code in bridge module must use C++17 standard with 2-space indentation, 120 column limit, and follow Chromium style guide as defined in `.clang-format` 

Applied to files:

  • bridge/bridge_sources.json5
  • bridge/CMakeLists.txt
📚 Learning: 2025-12-08T23:27:15.946Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/test/**/*.{cc,cpp} : Add bridge unit test files to `bridge/test/` directory and use Google Test macros: `TEST()`, `EXPECT_EQ()`, etc. Tests are automatically discovered by CMake 

Applied to files:

  • bridge/CMakeLists.txt
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to scripts/**/*.{js,json} : Set `ANDROID_STL=c++_static` as the default C++ standard library for Android builds 

Applied to files:

  • bridge/CMakeLists.txt
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to scripts/**/*.{js,json} : Bundle QuickJS into the WebF library for Android builds by default using static STL 

Applied to files:

  • bridge/CMakeLists.txt
🧬 Code graph analysis (8)
scripts/tasks.js (1)
integration_tests/scripts/core_integration_starter.js (1)
  • os (6-6)
integration_tests/specs/dom/intersection-observer.ts (3)
bridge/core/dom/intersection_observer.cc (2)
  • IntersectionObserver (41-46)
  • IntersectionObserver (48-94)
bridge/core/dom/intersection_observer_entry.cc (1)
  • IntersectionObserverEntry (30-46)
bridge/core/dom/intersection_observer_entry.d.ts (1)
  • IntersectionObserverEntry (11-25)
bridge/core/dom/document.h (1)
bridge/core/dom/document.cc (4)
  • RegisterIntersectionObserver (560-564)
  • RegisterIntersectionObserver (560-560)
  • UnregisterIntersectionObserver (566-575)
  • UnregisterIntersectionObserver (566-566)
bridge/core/dom/intersection_observer_entry.d.ts (1)
bridge/core/dom/intersection_observer_entry.cc (1)
  • IntersectionObserverEntry (30-46)
bridge/core/dom/intersection_observer.d.ts (3)
bridge/core/dom/intersection_observer_entry.h (1)
  • target (64-64)
bridge/core/dom/intersection_observer_entry.cc (1)
  • IntersectionObserverEntry (30-46)
bridge/core/dom/intersection_observer_entry.d.ts (1)
  • IntersectionObserverEntry (11-25)
bridge/core/dom/intersection_observer_entry.cc (4)
bridge/core/dom/intersection_observer_entry.d.ts (1)
  • IntersectionObserverEntry (11-25)
bridge/core/dom/intersection_observer_entry.h (1)
  • target (64-64)
bridge/core/dom/intersection_observer.cc (2)
  • Trace (282-286)
  • Trace (282-282)
bridge/core/binding_object.cc (2)
  • Trace (403-407)
  • Trace (403-403)
bridge/core/dom/document.cc (1)
bridge/core/dom/intersection_observer.cc (2)
  • Trace (282-286)
  • Trace (282-282)
bridge/core/dom/intersection_observer_entry.h (3)
bridge/core/dom/intersection_observer_entry.cc (3)
  • IntersectionObserverEntry (30-46)
  • Trace (48-53)
  • Trace (48-48)
bridge/core/dom/intersection_observer_entry.d.ts (1)
  • IntersectionObserverEntry (11-25)
bridge/core/binding_object.cc (2)
  • Trace (403-407)
  • Trace (403-403)
🪛 Biome (2.1.2)
bridge/core/dom/intersection_observer.d.ts

[error] 15-15: Don't use the new method in interfaces.

new in an interface suggests it's instantiable, which is incorrect. The returned type should different from the constructor's type.

(lint/suspicious/noMisleadingInstantiator)

bridge/core/dom/intersection_observer_init.d.ts

[error] 11-12: Decorators are not valid here.

Decorators are only valid on class declarations, class expressions, and class methods.

(parse)

🪛 GitHub Actions: Run Code Linter
bridge/CMakeLists.txt

[error] 334-334: Cannot find source file: code_gen/qjs_css_style_declaration.cc (add_library webf_core)


[error] 334-334: No SOURCES given to target: webf_core


[error] 1-1: CMake Generate step failed. Build files cannot be regenerated correctly.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build_bridge
  • GitHub Check: build_windows_bridge (Debug)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (rust)
Comment on lines +100 to +104
void IntersectionObserver::observe(Element* target, ExceptionState& exception_state) {
if (!RootIsValid() || !target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: observe valid:" << std::endl;
return;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Improve error message clarity.

The error log message on line 102 is incomplete and doesn't provide actionable information. It should clearly state what is invalid.

Apply this diff:

 if (!RootIsValid() || !target) { - WEBF_LOG(ERROR) << "[IntersectionObserver]: observe valid:" << std::endl; + WEBF_LOG(ERROR) << "[IntersectionObserver]: observe() called with invalid root or null target" << std::endl; return; }
📝 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
void IntersectionObserver::observe(Element* target, ExceptionState& exception_state) {
if (!RootIsValid() || !target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: observe valid:" << std::endl;
return;
}
void IntersectionObserver::observe(Element* target, ExceptionState& exception_state) {
if (!RootIsValid() || !target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: observe() called with invalid root or null target" << std::endl;
return;
}
🤖 Prompt for AI Agents
In bridge/core/dom/intersection_observer.cc around lines 100–104, the WEBF_LOG error message is vague; update it to explicitly state which condition failed (RootIsValid() false or null target) and include identifying info (e.g., target pointer or tag/name) so the log is actionable — change the log call to check the two conditions and emit a clear message like "observe failed: invalid root" or "observe failed: null target (target=<value>)" depending on which check fails. 
Comment on lines +106 to +109
#if ENABLE_LOG
WEBF_LOG(DEBUG) << "[IntersectionObserver]: observe target=" << target << ",tagName=" << target->nodeName()
<< std::endl;
#endif
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Replace Chinese punctuation with English comma.

The log message on line 107 contains a Chinese comma (,) instead of an English comma.

Apply this diff:

 #if ENABLE_LOG - WEBF_LOG(DEBUG) << "[IntersectionObserver]: observe target=" << target << ",tagName=" << target->nodeName() + WEBF_LOG(DEBUG) << "[IntersectionObserver]: observe target=" << target << ", tagName=" << target->nodeName() << std::endl; #endif
📝 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
#if ENABLE_LOG
WEBF_LOG(DEBUG) << "[IntersectionObserver]: observe target=" << target << "tagName=" << target->nodeName()
<< std::endl;
#endif
#if ENABLE_LOG
WEBF_LOG(DEBUG) << "[IntersectionObserver]: observe target=" << target << ", tagName=" << target->nodeName()
<< std::endl;
#endif
🤖 Prompt for AI Agents
In bridge/core/dom/intersection_observer.cc around lines 106 to 109, the log message uses a Chinese comma (,) between "target=" and "tagName="; replace that Chinese comma with an English comma so the log reads with a standard ASCII comma, preserving the surrounding text and spacing exactly. 
Comment on lines +128 to +132
void IntersectionObserver::unobserve(Element* target, ExceptionState& exception_state) {
if (!target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: unobserve valid:" << std::endl;
return;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Improve error message clarity.

The error log message on line 130 is incomplete and doesn't provide actionable information.

Apply this diff:

 if (!target) { - WEBF_LOG(ERROR) << "[IntersectionObserver]: unobserve valid:" << std::endl; + WEBF_LOG(ERROR) << "[IntersectionObserver]: unobserve() called with null target" << std::endl; return; }
📝 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
void IntersectionObserver::unobserve(Element* target, ExceptionState& exception_state) {
if (!target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: unobserve valid:" << std::endl;
return;
}
void IntersectionObserver::unobserve(Element* target, ExceptionState& exception_state) {
if (!target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: unobserve() called with null target" << std::endl;
return;
}
🤖 Prompt for AI Agents
In bridge/core/dom/intersection_observer.cc around lines 128-132, the existing log message "unobserve valid:" is incomplete; replace it with a clear, actionable message indicating that unobserve was called with a null/invalid target (for example: "[IntersectionObserver] unobserve called with null target") and include function context (e.g., function name) so logs show where the call originated; keep behavior the same (return on null) but improve the log text to explicitly state "null/invalid target" rather than the current ambiguous message. 
Comment on lines +2509 to +2520
bool addIntersectionObserver(IntersectionObserver observer, List<double> thresholds) {
if (_intersectionObserverList.contains(observer)) {
return false;
}
if (enableWebFCommandLog) {
domLogger.fine('[IntersectionObserver] attach target=$pointer observer=${observer.pointer} thresholds=$thresholds');
}
renderStyle.addIntersectionChangeListener(_handleIntersectionObserver, thresholds);
_intersectionObserverList.add(observer);
_thresholds = thresholds;
return true;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Observer list uses Set but the contains check and _thresholds overwrite could lead to inconsistent state.

The addIntersectionObserver method returns false if the observer already exists, but _thresholds is unconditionally set at line 2518. If the same observer tries to re-observe with different thresholds (which should update them per spec), the current logic would skip the update.

Additionally, _intersectionObserverList is declared as a Set<IntersectionObserver> but the type annotation on the field (line 103) shows it stores nullable references. The _elementList in IntersectionObserver is typed List<Element> but line 123 accesses it as element! suggesting potential null elements.

🤖 Prompt for AI Agents
In webf/lib/src/dom/element.dart around lines 2509-2520, the addIntersectionObserver method sets _thresholds unconditionally and returns false early, which prevents updating thresholds when an existing observer re-observes, and the observer collection and element lists have nullable types that cause unsafe force-unwrapping. Change the logic so that if _intersectionObserverList.contains(observer) you compare the new thresholds to the stored thresholds and, if they differ, update _thresholds and re-register/update the renderStyle listener (call renderStyle.addIntersectionChangeListener with the new thresholds) before returning false; otherwise return false without changing state. Also make _intersectionObserverList a non-nullable Set<IntersectionObserver> (remove nullable element type), and either make IntersectionObserver._elementList non-nullable List<Element> or add null-safety checks where element! is accessed (ensure elements added are non-null or guard usages), so no force-unwrapping of potentially null elements remains. 
Comment on lines +54 to +56
List<double> _thresholds = [0.0];
int _lastThresholdsIndex = 0;
bool _lastIsIntersecting = false;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix _thresholds! null‑check and ensure thresholds are applied consistently

  • _thresholds is declared as non‑nullable (List<double> _thresholds = [0.0];) but used as _thresholds! in _dispatchChange, which is invalid under NNBD and will be rejected by the analyzer/compiler. This should just pass _thresholds directly to firstThresholdGreaterThan(...).
  • copyTo copies _listeners but not _thresholds, _lastThresholdsIndex, or _lastIsIntersecting, so a cloned render object may compute threshold crossings using the default [0.0] rather than the thresholds actually used when the observer was created. This can lead to extra / missing callbacks after layout moves.

Consider:

- List<double> _thresholds = [0.0]; + List<double> _thresholds = const [0.0]; ... - int index = firstThresholdGreaterThan(info.intersectionRatio, _thresholds!); + final thresholds = _thresholds; + final index = firstThresholdGreaterThan(info.intersectionRatio, thresholds);

and extending copyTo to also copy the threshold state:

 static copyTo(RenderIntersectionObserverMixin from, RenderIntersectionObserverMixin to) { to.intersectPadding = from.intersectPadding; to._listeners = from._listeners; + to._thresholds = from._thresholds; + to._lastThresholdsIndex = from._lastThresholdsIndex; + to._lastIsIntersecting = from._lastIsIntersecting; to._onIntersectionChange = to._dispatchChange;

Also applies to: 70-82, 113-168

🤖 Prompt for AI Agents
In webf/lib/src/rendering/intersection_observer.dart around lines 54-56 (and also review usages in 70-82 and 113-168), remove the invalid null-check `_thresholds!` and pass `_thresholds` directly to firstThresholdGreaterThan(...) (NNBD requires no ! for a non-nullable field), and update the copyTo method to copy the threshold state from the source render object by assigning `_thresholds`, `_lastThresholdsIndex`, and `_lastIsIntersecting` in addition to `_listeners` so cloned render objects preserve the same thresholds and last-intersection state and avoid incorrect/missed callbacks after layout moves. 
Comment on lines 84 to 96
void clearIntersectionChangeListeners() {
_clearIntersectionListeners = true;
}

void _clearIntersectionChangeListeners() {
_listeners?.clear();
_listeners = null;
_onIntersectionChange = null;
_clearIntersectionListeners = false;
_lastThresholdsIndex = 0;
_lastIsIntersecting = false;
}

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Listener clearing is deferred and may never run; tighten lifecycle semantics

clearIntersectionChangeListeners() only flips _clearIntersectionListeners = true; actual clearing happens inside _dispatchChange() when it next runs. If clearIntersectionChangeListeners() is called while there are no further intersection updates (e.g., observer disconnect() on a stable target), _listeners and _onIntersectionChange may never be cleared, keeping callbacks and related objects alive longer than necessary.

You likely want:

  • Immediate clear when not currently dispatching.
  • Deferred clear only when invoked during a dispatch to avoid concurrent modification.

A minimal fix is to track an _inDispatch flag:

+ bool _inDispatch = false; void clearIntersectionChangeListeners() { - _clearIntersectionListeners = true; + if (_inDispatch) { + _clearIntersectionListeners = true; + } else { + _clearIntersectionChangeListeners(); + } } bool _dispatchChange(IntersectionObserverEntry info) { - bool deliverIntersectionObserver = false; + _inDispatch = true; + bool deliverIntersectionObserver = false; ... - if (_clearIntersectionListeners) { - _clearIntersectionChangeListeners(); - } + if (_clearIntersectionListeners) { + _clearIntersectionChangeListeners(); + } + _inDispatch = false; return deliverIntersectionObserver; }

Also applies to: 113-137

🤖 Prompt for AI Agents
In webf/lib/src/rendering/intersection_observer.dart around lines 84-96 (and similarly update lines 113-137), clearIntersectionChangeListeners() currently just sets _clearIntersectionListeners = true and relies on _dispatchChange() to do the real clearing, which can leave listeners alive if no further dispatch occurs; add a private boolean _inDispatch that _dispatchChange() sets true while iterating and false afterwards, and change clearIntersectionChangeListeners() to immediately clear _listeners, _onIntersectionChange and reset related fields when _inDispatch is false, but if _inDispatch is true then keep setting _clearIntersectionListeners = true so the actual clearing happens after dispatch completes; update _dispatchChange() to check _clearIntersectionListeners after dispatch and perform the same clear operation, and ensure both places reset _clearIntersectionListeners and other state consistently. 
Copy link

@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: 2

🧹 Nitpick comments (2)
bridge/core/dom/intersection_observer_entry.h (2)

64-64: Remove or explain commented-out code.

The commented-out IntersectionGeometry geometry_; member should either be removed entirely or accompanied by a TODO/FIXME comment explaining why it's preserved.


52-52: Consider adding [[nodiscard]] to nullable accessor.

The rootBounds() accessor can return nullptr (as indicated by the TypeScript interface showing BoundingClientRect | null). Adding [[nodiscard]] would encourage callers to check the return value.

Apply this diff:

- BoundingClientRect* rootBounds() const { return root_bounds_.Get(); } + [[nodiscard]] BoundingClientRect* rootBounds() const { return root_bounds_.Get(); }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46a1bfd and 01a2744.

📒 Files selected for processing (2)
  • bridge/core/dom/intersection_observer.h (1 hunks)
  • bridge/core/dom/intersection_observer_entry.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • bridge/core/dom/intersection_observer.h
🧰 Additional context used
📓 Path-based instructions (4)
bridge/**/*.{cc,cpp,h,hpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{cc,cpp,h,hpp}: C++ code should follow Chromium style (.clang-format) with C++17 standard, 120 character column limit, and 2-space indentation
Use WEBF_EXPORT_C macro for exporting C functions to Dart FFI
In FFI contexts, use Dart_Handle instead of Handle for type compatibility
For C++ FFI function naming: use GetObjectPropertiesFromDart for C++ exports, NativeGetObjectPropertiesFunc for Dart typedefs, and GetObjectPropertiesFunc for Dart functions
Lambda signatures in C++ must match expected function signatures to avoid FFI type mismatches
Choose power-of-2 buffer sizes (512, 1024, 2048) for ring buffer implementation, with smaller sizes for DEBUG_BUILD, MOBILE constraints, and larger sizes for DESKTOP performance

Files:

  • bridge/core/dom/intersection_observer_entry.h
bridge/**/*.{h,hpp}

📄 CodeRabbit inference engine (bridge/CLAUDE.md)

bridge/**/*.{h,hpp}: Ring buffer command structure should use enum Type : uint8_t for command types with union for type-specific data to ensure type-safe and cache-friendly command handling
Ring buffer implementation should use alignas(64) for atomic head and tail pointers, std::atomic<size_t> for thread-safe synchronization, and power-of-2 buffer sizes enforced with static_assert

Files:

  • bridge/core/dom/intersection_observer_entry.h
bridge/**/*.{cc,h}

📄 CodeRabbit inference engine (AGENTS.md)

C++ code in bridge module must use C++17 standard with 2-space indentation, 120 column limit, and follow Chromium style guide as defined in .clang-format

bridge/**/*.{cc,h}: Use RAII patterns in C++ where possible for resource management
Use PostToJs for executing operations on the JS thread in FFI
Use PostToDart for returning results to Dart isolate
Avoid PostToJsSync synchronous execution when possible

Files:

  • bridge/core/dom/intersection_observer_entry.h
{bridge/**/*.{cc,h},webf/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

Document memory ownership clearly in FFI implementations

Files:

  • bridge/core/dom/intersection_observer_entry.h
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR Repo: openwebf/webf PR: 0 File: bridge/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:27:15.946Z Learning: Applies to bridge/**/*.{cc,cpp} : Use PostToJs for executing operations on the JS thread from other threads, PostToDart for returning results to Dart isolate, and avoid PostToJsSync to prevent deadlocks 
📚 Learning: 2025-12-08T23:28:00.818Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: webf/CLAUDE.md:0-0 Timestamp: 2025-12-08T23:28:00.818Z Learning: Applies to webf/lib/bridge.dart : lib/bridge.dart contains FFI bindings to C++ bridge 

Applied to files:

  • bridge/core/dom/intersection_observer_entry.h
📚 Learning: 2025-12-13T16:32:47.644Z
Learnt from: CR Repo: openwebf/webf PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-12-13T16:32:47.644Z Learning: Applies to webf/**/*.dart : Track pointer ownership in callbacks within Dart FFI 

Applied to files:

  • bridge/core/dom/intersection_observer_entry.h
🧬 Code graph analysis (1)
bridge/core/dom/intersection_observer_entry.h (5)
bridge/core/dom/intersection_observer.h (1)
  • webf (18-97)
bridge/core/dom/intersection_observer_entry.d.ts (1)
  • IntersectionObserverEntry (11-25)
bridge/core/dom/intersection_observer_entry.cc (3)
  • IntersectionObserverEntry (30-46)
  • Trace (48-53)
  • Trace (48-48)
bridge/core/binding_object.cc (2)
  • Trace (403-407)
  • Trace (403-403)
bridge/core/dom/node_rare_data.h (1)
  • Member (52-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build_windows_bridge (Debug)
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (c-cpp)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
bridge/core/dom/intersection_observer_entry.h (1)

35-48: LGTM! Well-designed class declaration.

The deleted default constructor ensures explicit initialization, and the explicit constructor signature provides all necessary parameters for proper setup. This aligns with RAII best practices recommended in the coding guidelines.

Comment on lines +21 to +28
struct NativeIntersectionObserverEntry : public DartReadable {
int8_t is_intersecting;
double intersectionRatio;
NativeBindingObject* target;
NativeBindingObject* boundingClientRect;
NativeBindingObject* rootBounds;
NativeBindingObject* intersectionRect;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing fields in FFI struct may cause data loss when marshalling to Dart.

The NativeIntersectionObserverEntry struct is missing time and is_visible fields that are present in the IntersectionObserverEntry C++ class (lines 68, 67) and exposed in the TypeScript interface. The PR description specifically mentions implementing the time field as part of this work.

Apply this diff to add the missing fields:

 struct NativeIntersectionObserverEntry : public DartReadable { int8_t is_intersecting; + int8_t is_visible; double intersectionRatio; + int64_t time; NativeBindingObject* target; NativeBindingObject* boundingClientRect; NativeBindingObject* rootBounds; NativeBindingObject* intersectionRect; };

As per coding guidelines, document memory ownership clearly in FFI implementations.

Comment on lines +30 to +33
struct NativeIntersectionObserverEntryList : public DartReadable {
NativeIntersectionObserverEntry* entries;
int32_t length;
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Document memory ownership for FFI array structure.

Add documentation clarifying:

  • Whether the entries array is owned by the caller or callee
  • Expected lifetime of the array and its elements
  • Who is responsible for deallocation

As per coding guidelines, document memory ownership clearly in FFI implementations.

🤖 Prompt for AI Agents
In bridge/core/dom/intersection_observer_entry.h around lines 30 to 33, the NativeIntersectionObserverEntryList struct lacks FFI memory-ownership documentation; add a clear comment above the struct that states whether entries is owned by the caller or callee, the expected lifetime of the entries array and each NativeIntersectionObserverEntry element (e.g. valid until a specific API call or explicit free), and who must free the memory (e.g. caller must call freeEntries or callee will free on next tick). Keep the comment concise and concrete (ownership rule, lifetime guarantee, deallocation function or responsibility) to satisfy FFI coding guidelines. 
@andycall andycall merged commit e78892a into main Dec 15, 2025
37 of 39 checks passed
@andycall andycall deleted the feat/add_intersection_observer_new branch December 15, 2025 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants