From bb0a8ef6fa06a93a3c4ef89bce04b72f2eb4be51 Mon Sep 17 00:00:00 2001 From: Oskar Eichler Date: Mon, 31 Aug 2026 02:52:05 +0300 Subject: [PATCH] Guard private syntax preservation by profile --- .../src/__tests__/transform-snapshot-test.js | 19 +++++++++++++++++++ .../src/configs/main.js | 11 +++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/react-native-babel-preset/src/__tests__/transform-snapshot-test.js b/packages/react-native-babel-preset/src/__tests__/transform-snapshot-test.js index 1e972039ee5..eb778e8e87a 100644 --- a/packages/react-native-babel-preset/src/__tests__/transform-snapshot-test.js +++ b/packages/react-native-babel-preset/src/__tests__/transform-snapshot-test.js @@ -444,6 +444,25 @@ describe('react-native-babel-preset transform snapshots', () => { expect(result).toContain('_classPrivateFieldLooseKey'); }); + it('transforms private class fields when the profile lowers classes', () => { + const code = ` + class Counter { + #count = 0; + #privateMethod() { return this.#count; } + } + `; + const result = transformCode(code, { + dev: false, + unstable_transformProfile: 'hermes-legacy', + customTransformOptions: { + unstable_preserveClassPrivate: true, + }, + }); + expect(result).not.toContain('#count'); + expect(result).not.toContain('#privateMethod'); + expect(result).toContain('_classPrivateFieldLooseKey'); + }); + it('preserves async/await with unstable_preserveAsync', () => { const code = ` async function fetchData() { diff --git a/packages/react-native-babel-preset/src/configs/main.js b/packages/react-native-babel-preset/src/configs/main.js index a48b126ca8b..86c5f69b6cb 100644 --- a/packages/react-native-babel-preset/src/configs/main.js +++ b/packages/react-native-babel-preset/src/configs/main.js @@ -94,10 +94,13 @@ const getPreset = (src, options, babel) => { // Preserve class syntax and related features for Hermes V1 profiles. const preserveClasses = isHermesProfile; - // Preserve private class fields and methods if the experiment is enabled. - const preserveClassPrivate = TRUE_VALS.has( - options?.customTransformOptions?.unstable_preserveClassPrivate, - ); + // Private fields can only be preserved when the surrounding class syntax is + // also preserved. Babel's class transform requires the private transforms. + const preserveClassPrivate = + preserveClasses && + TRUE_VALS.has( + options?.customTransformOptions?.unstable_preserveClassPrivate, + ); // Preserve async/await syntax if the experiment is enabled. const preserveAsync = TRUE_VALS.has(