Pieter De Baets
90d · built 2026-09-08
Performance
What Pieter De Baets shipped in the selected window, measured in ETV, and how it compares with the 90 days before it.
Effective capacity
−0.3engineers
delivers like 0.7 (0.7x pre-AI)
Output (ETV)
4.7ETV
−53.7% vs 10.1 prior
Features share
18.3%
−2.1 pp vs prior window
Fixes share
15.1%
+6.5 pp vs prior window
Work mix
18.3% Features49.3% Maintenance15.4% Tests1.9% Docs15.1% Fixes
53 commits over 90 days, ending 2026-09-08.
Daily performance
Daily ETV, stacked by Features, Maintenance, Tests, Docs and Fixes.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
| Repo | Commits | ETV |
|---|---|---|
| react-native | 45 | 4.5 |
| react | 4 | 0.2 |
Most impactful commits
Top 10 by ETV in the last 90 days.
- 0.6ETVRemove useOptimizedViewRegistryOnAndroid feature flag (#57228) Summary: Pull Request resolved: https://github.com/react/react-native/pull/57228 The flag gated a more memory-efficient view registry implementation in `SurfaceMountingManager` (`MutableIntObjectMap` with a `ReadWriteLock` instead of `ConcurrentHashMap`). Removing the gate, keeping the optimized path, and inlining the helper methods that previously dispatched between the two implementations. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D108415790 fbshipit-source-id: b21cbb1923cf7d15e375df8d3c3c51d187eecee3github.com-facebook-react-native · 723908a7 · 2026-06-16
- 0.4ETVAdd IntBuffer and DoubleBuffer entry types to MapBuffer (#57359) Summary: Pull Request resolved: https://github.com/react/react-native/pull/57359 Adds two new MapBuffer entry types, `IntBuffer` and `DoubleBuffer`, for storing homogeneous arrays of ints and doubles compactly in the dynamic data section. Unlike `Map` / map lists, these carry no per-element key/type overhead: a batch of N values costs ~N*elementSize bytes plus a single 4-byte count prefix instead of N 12-byte buckets. The bucket value holds the offset of the array within the dynamic data section. Covers the full surface: the C++ reader (`MapBuffer::getIntBuffer` / `getDoubleBuffer`), the C++ builder (`MapBufferBuilder::putIntBuffer` / `putDoubleBuffer`), and the Kotlin reader API (`MapBuffer.getIntBuffer` / `getDoubleBuffer`, `Entry.intBufferValue` / `doubleBufferValue`). The `DataType` enum gains `IntBuffer = 6` and `DoubleBuffer = 7`, kept in sync across C++ and Kotlin. Changelog: [General][Added] - Add `IntBuffer` and `DoubleBuffer` entry types to MapBuffer for compact homogeneous int/double arrays landed-with-radar-review Reviewed By: zeyap Differential Revision: D109848476 fbshipit-source-id: f9e86b7c094dea796d9a8b725e53eb948c1390cagithub.com-facebook-react-native · e7cadaf9 · 2026-07-03
- 0.4ETVBuffer async CallInvoker work with module calls (#58313) Summary: Pull Request resolved: https://github.com/react/react-native/pull/58313 In bridgeless, native reaches JS by two routes that end in the same `RuntimeScheduler` queue but get there differently. `callFunctionOnModule` goes through the instance's `BufferedRuntimeExecutor`; the `CallInvoker` goes straight to `scheduleTask`. The CallInvoker therefore skips the buffer entirely and can reach the runtime while a module call issued earlier is still parked, unflushed, because the bundle is mid-evaluation. Native code that issues both cannot rely on the order it issued them in, and `Task` is a min-heap on `now() + timeout(priority)` with no insertion tiebreak, so equal priorities do not settle it either. Gives the two channels the same buffering. `BufferedRuntimeExecutor` gains a priority-carrying `execute`, so work routed through it keeps the scheduler priority it was submitted with instead of collapsing to the executor default, and buffered work from both overloads stays in one submission-ordered stream. `BufferedCallInvoker` sits on that executor and becomes the bridgeless `jsCallInvoker` on Android, iOS and macOS. `invokeSync` deliberately keeps going straight to the scheduler: a synchronous call cannot wait for a flush that only happens once the bundle has run. Behind `enableBufferedCallInvoker`, default true. `ReactInstance` picks between the buffered invoker and the existing `RuntimeSchedulerCallInvoker` in one place, so the platform call sites are identical either way and the change is revertible at runtime — it moves when native-issued async work first reaches JS during startup, which is the intended contract but affects every native module. One lifetime hazard this surfaces, worth knowing about beyond this diff: `BufferedRuntimeExecutor` reaches the scheduler through a raw pointer captured at construction, which is safe only while the owning instance is alive. A CallInvoker is routinely held across instance teardown, so `BufferedCallInvoker` guards every async dispatch on a weak reference to the scheduler and drops the work when it has expired — the same contract `RuntimeSchedulerCallInvoker` has. Without that guard this reliably segfaults on a reload. Changelog: [General][Changed] - Async `CallInvoker` work is now buffered alongside callable module calls, so it no longer runs before the JS bundle has finished evaluating Reviewed By: rubennorte Differential Revision: D118456662 fbshipit-source-id: 7c6ccb595d69595721092eeb84b4724809140496github.com-facebook-react-native · 3ca6ea3e · 2026-09-04
- 0.3ETVOptimize MapBuffer representation (#57361) Summary: Pull Request resolved: https://github.com/react/react-native/pull/57361 Broadens the former header-shrink change into a single representation-optimization commit for MapBuffer. It bundles three layout optimizations that were previously split: (1) the header is reduced to a single 2-byte `count` field; (2) multi-byte values are read via `memcpy` so unaligned access is well-defined on all platforms; (3) every dynamic-data entry (`String`, `Map`, `MapBufferList`, `IntBuffer`, `DoubleBuffer`) packs its `[offset][byteLength]` into the bucket's 8-byte value instead of writing an in-band length prefix into the dynamic data section. Net effect: 4 fewer bytes per dynamic entry, one fewer indirection on read (the length is already in the bucket), and every dynamic entry becomes self-delimiting from its bucket alone. No public API change — only the internal serialized representation. Changelog: [Internal] landed-with-radar-review Reviewed By: lenaic, zeyap Differential Revision: D109848478 fbshipit-source-id: 30749aaa1c2d9fc9b1f8684a3b67815ef44632e8github.com-facebook-react-native · 803456d6 · 2026-07-03
- 0.3ETVRoute `enableCppPropsIteratorSetter` through a copy ctor + `RawProps::forEachItem` (#57328) Summary: Pull Request resolved: https://github.com/react/react-native/pull/57328 Today the iterator-setter path in `ConcreteComponentDescriptor::cloneProps` runs three sequential walks over the input — `RawProps::parse(parser)` (builds `keyIndexToValueIndex_` for `convertRawProp`), `static_cast<folly::dynamic>(rawProps)` (materializes a `folly::dynamic` via `jsi::dynamicFromValue` in JSI mode), and then `dynamic.items()` to dispatch `setProp`. Only the third is actually used: `convertRawProp` is never called on the iterator-setter branch, and the `folly::dynamic` materialization exists only as iteration scaffolding. Restructure so the runtime flag picks one of two construction paths up front: - **Iterator-setter** — copy-construct from `sourceProps` via the (re-enabled) `Props` copy ctor, then walk `rawProps` in-place via the new `RawProps::forEachItem` helper and route each entry through `setProp`. `parse()` is skipped entirely; the `folly::dynamic` materialization is skipped in `Mode::JSI`. - **Classic** — unchanged: `parse()` + 3-arg `convertRawProp`-driven ctor. `forEachItem` switches on `RawProps::Mode`: - `Mode::JSI` — walks `value_.asObject(*runtime_).getPropertyNames(...)` and constructs `RawValue` from each `jsi::Value` directly, no `folly::dynamic` in between. - `Mode::Dynamic` — iterates `dynamic_.items()` (same as today). - `Mode::Empty` — no-op. A new `HasIteratorSetterCtor<T>` concept (`std::copy_constructible<T>`) documents the contract and feeds a `static_assert` in `cloneProps`, so a future Props type that deletes its copy ctor fails at compile time rather than silently diverging at runtime between the two flag states. The `RN_SERIALIZABLE_STATE` Props 2.0 accumulation branch keeps its existing dynamic-iteration shape — when `fallbackToDynamicRawPropsAccumulation` is true, `initializeDynamicProps` has already merged the source's rawProps with the input onto `shadowNodeProps->rawProps`, so we iterate that merged dynamic rather than the raw input. The per-field `flag ? sourceProps.X : convertRawProp(...)` ternaries across every Props .cpp file become dead in the flag-on path (the copy ctor handles those fields) but are still functional in the flag-off path. They get removed in a follow-up cleanup; this diff is structurally non-breaking on either flag state. Changelog: [Internal] Reviewed By: zeyap Differential Revision: D109568749 fbshipit-source-id: eae20478418a7dbf7364c73d85d7694d99f1e8f1github.com-facebook-react-native · c1d8ae97 · 2026-07-06
- 0.3ETVRemove RawPropsKey prefix and suffix Summary: X-link: https://github.com/facebook/react-native/pull/55763 RawPropsKey previously stored three `const char*` fields (prefix, name, suffix) that were concatenated at runtime to form property names. This is pretty niche, used to make a few patterns simpler, but also can lead to confusing conflicts when the same property name can be represented in different ways (e.g. T174300106). Iterator style props parsing also completely avoids it. Lets change the API to a flat name instead. This change is breaking, but could only find a single user (Nitro module) effected, searching through `react-native-libraries`. Changelog: [General][Breaking] - Remove RawPropsKey prefix and suffix Reviewed By: christophpurrer Differential Revision: D94367880 fbshipit-source-id: d865725c7be6f880760b6e8d1a567a1b12ac469agithub.com-facebook-react-native · 67381e15 · 2026-06-25
- 0.2ETVReduce JNI allocations when importing native maps (#58274) Summary: Pull Request resolved: https://github.com/react/react-native/pull/58274 `ReadableNativeMap` materialization copied keys and created temporary JNI references for every imported type. Cache pointers to the stable native values and reuse global `ReadableType` references so importing maps and arrays does less allocation and lookup work. Writable maps can continue mutating after materialization because `folly::dynamic` stores object entries in reference-stable `F14NodeMap` nodes. Changelog: [Internal] Reviewed By: christophpurrer, rubennorte Differential Revision: D118277119 fbshipit-source-id: 955a60ef7f1eb4cb7549d64caa1238416e90b223github.com-facebook-react-native · bf0e377c · 2026-09-04
- 0.2ETVDrop per-field `enableCppPropsIteratorSetter` ternaries from Props ctors (#57418) Summary: Pull Request resolved: https://github.com/react/react-native/pull/57418 With `ConcreteComponentDescriptor::cloneProps` now dispatching to the iterator-setter path via the copy ctor (the prior diffs in the stack), the per-field `flag ? sourceProps.X : convertRawProp(...)` ternaries scattered across every Props copy ctor are dead in the flag-on path (copy ctor handles those fields directly) and redundant in the flag-off path (the runtime check inside the ctor is always false, since cloneProps already filtered the iterator-setter path out before invoking the 3-arg ctor). Strip the ternary wrapper from every Props .cpp file. Each initializer collapses from ```cpp field(ReactNativeFeatureFlags::enableCppPropsIteratorSetter() ? sourceProps.field : convertRawProp(ctx, rawProps, "field", sourceProps.field, default)) ``` to just ```cpp field(convertRawProp(ctx, rawProps, "field", sourceProps.field, default)) ``` Also strip: - `YogaStylableProps`: the inverted `if (!flag) { convertRawPropAliases(...); }` wrapper becomes unconditional. - `Props::initialize` (`Props.cpp`): the `nativeId` ternary collapses to the `convertRawProp` form. - `AccessibilityProps` (xplat + react-native-macos): the `if (flag) { copy } else { at()-based resolution }` block in the constructor body collapses to just the `at()`-based resolution — the same reasoning applies (flag-on path never reaches the 3-arg ctor). - Drop `<react/featureflags/ReactNativeFeatureFlags.h>` includes that are no longer referenced. 311 ternaries removed across 20 Props .cpp files (incl. the `third-party/react-native-macos/` mirror and `xplat/instagram/airwave/components/airwavescrollview/cpp/AirwaveScrollViewProps.cpp`). Side benefit: the classic path is now meaningfully cheaper because we no longer do `~30 × ReactNativeFeatureFlags::enableCppPropsIteratorSetter()` calls (each goes through `std::atomic<std::optional<bool>>::load()`) per `cloneProps` invocation per Props class. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D109583086 fbshipit-source-id: f25783cc7fdcf485ed01f63da9a6eea473bfc1d3github.com-facebook-react-native · 1172a8a5 · 2026-07-06
- 0.2ETVFix ctor/setProp prop-name gaps surfaced by iterator-setter audit (#57330) Summary: Pull Request resolved: https://github.com/react/react-native/pull/57330 Auditing every Props .cpp file in the renderer surfaced six cases where a prop key parsed by the 3-arg constructor's `convertRawProp(...)` call had no matching `case` in the same class's `setProp` method. With the iterator-setter path now routing every prop through `setProp` (instead of re-running the parsing constructor), each gap silently drops the prop on the floor when the iterator-setter path is active. Fix each gap: - `BaseScrollViewProps::setProp` — add `RAW_SET_PROP_SWITCH_CASE_BASIC(automaticallyAdjustKeyboardInsets)`. Parsed in ctor, missing case. - `BaseTextProps::setProp` — add `REBUILD_FIELD_SWITCH_CASE(... dynamicTypeRamp, "dynamicTypeRamp")`. Parsed in ctor, missing case. - `BaseTextProps::setProp` — rename the `baseWritingDirection` switch case key to `writingDirection`. JS sends `writingDirection` (the C++ field is named `baseWritingDirection` internally, but JS / Flow / TS / codegen all use `writingDirection` — verified across `StyleSheetTypes.js`, `StyleSheetTypes.d.ts`, `ReactNativeStyleAttributes.js`, `RCTTextInputViewConfig.js`, and the `Text-itest.js` integration test mounts `<rn-paragraph writingDirection="rtl">`). The setProp case was keyed off the C++ field name and never fired for any real JS prop. `appendTextAttributesProps` still emits `baseWritingDirection` for the C++→JS diff path — that's a separate, out-of-scope inconsistency. - `AccessibilityProps::setProp` — rename the `accessibilityOrder` switch case key to `experimental_accessibilityOrder`. JS sends the prefixed name (verified in `ViewPropTypes.js`, `BaseViewConfig.android.js`, `BaseViewConfig.ios.js`, `ViewProps.kt`'s `ACCESSIBILITY_ORDER = "experimental_accessibilityOrder"` constant, and `HostPlatformViewProps::getDebugProps` which serializes back out as `experimental_accessibilityOrder`). The unprefixed case never fired. - `BaseViewProps::setProp` — add `RAW_SET_PROP_SWITCH_CASE_BASIC(transformOrigin)`. Parsed in ctor, missing case. - `BaseViewProps::setProp` — add `SET_CASCADED_RECTANGLE_CORNERS(borderCurves, "border", "Curve", value)`. The ctor parses the full 13-key cascaded set (`borderCurve`, `borderTopLeftCurve`, … `borderStartStartCurve`) via `CascadedRectangleCornersNames`, but `setProp` had `SET_CASCADED_RECTANGLE_CORNERS` for `borderRadii` and `SET_CASCADED_RECTANGLE_EDGES` for `borderColors`/`borderStyles` — the corresponding `borderCurves` invocation was missing. Same gaps in the `third-party/react-native-macos/.../BaseViewProps.cpp` mirror — applied the same fixes there. Out-of-scope but flagged by the audit (left for follow-ups): - `propsConversions.h`'s `ViewEvents` converter doesn't handle `onGotPointerCapture` / `onLostPointerCapture` (explicit `// TODO` at line 541). `BaseViewProps::setProp` does. Asymmetry runs the other direction — iterator-setter handles these, classic ctor doesn't. - android `HostPlatformViewProps.cpp` defines `VIEW_EVENT_CASE` macro but never invokes it in its switch — dead code (events live on `BaseViewProps::events`). Cleanup candidate. Changelog: [General][Fixed] - Several view, text, scrollview, and accessibility props that the iterator-setter path silently dropped now propagate correctly through `setProp`: `automaticallyAdjustKeyboardInsets`, `dynamicTypeRamp`, `writingDirection`, `experimental_accessibilityOrder`, `transformOrigin`, and the full `borderCurves` cascaded set. Reviewed By: christophpurrer Differential Revision: D109584760 fbshipit-source-id: e79b2e235ee49024bb03c248ef8cce10e3bbcd83github.com-facebook-react-native · 15b1f552 · 2026-06-29
- 0.1ETV[compiler] Restore code frames in ESLint compiler error messages (#36901) ## Summary The Rust port (#36173) changed `CompileError` `LoggerEvent`s to carry plain serialized detail objects instead of `CompilerError`/`CompilerDiagnostic` class instances. As a result, the ESLint integrations could no longer call `detail.printErrorMessage(source, {eslint: true})` and were given a replacement `printErrorMessage()` helper that only emitted the `reason` and `description`. This regressed error printing: the **source code frame(s) and `file:line:column` location** that used to appear for each error detail were dropped from lint output. This PR restores the previous behaviour: - Export `printCodeFrame` from `CompilerError` and reuse it from both ESLint integrations instead of duplicating it. - Rebuild the full message (reason, description, per-detail code frames, and hints) in `printErrorMessage`. - Handle **both** detail shapes that flow through `LoggerEvent`s: - a `details` array (`CompilerDiagnostic` and the **Rust** compiler), and - a legacy flat `loc` (deprecated `CompilerErrorDetail`). `formatDetailForLogging` emits one or the other, so the previous unconditional iteration over `error.details` would have thrown `TypeError: not iterable` on the flat-`loc` path. Normalizing to a list fixes that and keeps the code working with both the TypeScript and Rust compilers. ## Test plan - `tsc --noEmit` on both ESLint packages is clean (no new errors vs. baseline). - Verified the detail loop handles the Rust compiler's `details` array shape and the legacy flat `loc` shape.github.com-facebook-react · 9c1f0977 · 2026-06-30