Back out "Implement new feature flag system"

Summary:
Original commit changeset: 0ba95803f61e

Original Phabricator Diff: D52806730

bypass-github-export-checks

changelog: [internal] internal

Reviewed By: yungsters

Differential Revision: D53113947

fbshipit-source-id: ace1222a861a739fcd3f4b0e12c135db47a93344
This commit is contained in:
David Vacca 2024-01-25 21:52:59 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 31a8bc9644
Коммит ffaeaba213
73 изменённых файлов: 4 добавлений и 3126 удалений

Просмотреть файл

@ -21,8 +21,6 @@
"flow": "flow",
"format-check": "prettier --list-different \"./**/*.{js,md,yml,ts,tsx}\"",
"format": "npm run prettier && npm run clang-format",
"featureflags-check": "cd packages/react-native && yarn featureflags-check",
"featureflags-update": "cd packages/react-native && yarn featureflags-update",
"lint-ci": "./scripts/circleci/analyze_code.sh && yarn shellcheck",
"lint-java": "node ./scripts/lint-java.js",
"lint": "eslint .",

Просмотреть файл

@ -129,7 +129,6 @@ Pod::Spec.new do |s|
s.dependency "React-jsi"
s.dependency "React-jsiexecutor"
s.dependency "React-utils"
s.dependency "React-featureflags"
s.dependency "SocketRocket", socket_rocket_version
s.dependency "React-runtimescheduler"
s.dependency "Yoga"

Просмотреть файл

@ -526,7 +526,6 @@ android {
"runtimeexecutor",
"react_codegen_rncore",
"react_debug",
"react_featureflags",
"react_utils",
"react_render_componentregistry",
"react_newarchdefaults",
@ -541,7 +540,6 @@ android {
"jsi",
"glog",
"fabricjni",
"featureflagsjni",
"react_render_mapbuffer",
"yoga",
"folly_runtime",

Просмотреть файл

@ -1,78 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<c201b2b577ab4aa4bf6071d6b99b43c9>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
package com.facebook.react.internal.featureflags
/**
* This object provides access to internal React Native feature flags.
*
* All the methods are thread-safe if you handle `override` correctly.
*/
object ReactNativeFeatureFlags {
private var accessorProvider: () -> ReactNativeFeatureFlagsAccessor = { ReactNativeFeatureFlagsCxxAccessor() }
private var accessor: ReactNativeFeatureFlagsAccessor = accessorProvider()
/**
* Common flag for testing. Do NOT modify.
*/
fun commonTestFlag() = accessor.commonTestFlag()
/**
* Overrides the feature flags with the ones provided by the given provider
* (generally one that extends `ReactNativeFeatureFlagsDefaults`).
*
* This method must be called before you initialize the React Native runtime.
*
* @example
*
* ```
* ReactNativeFeatureFlags.override(object : ReactNativeFeatureFlagsDefaults() {
* override fun someFlag(): Boolean = true // or a dynamic value
* })
* ```
*/
fun override(provider: ReactNativeFeatureFlagsProvider) = accessor.override(provider)
/**
* Removes the overridden feature flags and makes the API return default
* values again.
*
* This should only be called if you destroy the React Native runtime and
* need to create a new one with different overrides. In that case,
* call `dangerouslyReset` after destroying the runtime and `override`
* again before initializing the new one.
*/
fun dangerouslyReset() {
// This is necessary when the accessor interops with C++ and we need to
// remove the overrides set there.
accessor.dangerouslyReset()
// This discards the cached values and the overrides set in the JVM.
accessor = accessorProvider()
}
/**
* This is just used to replace the default ReactNativeFeatureFlagsCxxAccessor
* that uses JNI with a version that doesn't, to simplify testing.
*/
internal fun setAccessorProvider(newAccessorProvider: () -> ReactNativeFeatureFlagsAccessor) {
accessorProvider = newAccessorProvider
accessor = accessorProvider()
}
}

Просмотреть файл

@ -1,14 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.internal.featureflags
interface ReactNativeFeatureFlagsAccessor : ReactNativeFeatureFlagsProvider {
fun override(provider: ReactNativeFeatureFlagsProvider)
fun dangerouslyReset()
}

Просмотреть файл

@ -1,38 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<961f1fb0a7ad802a492437f15b1f2dcb>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
package com.facebook.react.internal.featureflags
class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccessor {
private var commonTestFlagCache: Boolean? = null
override fun commonTestFlag(): Boolean {
var cached = commonTestFlagCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.commonTestFlag()
commonTestFlagCache = cached
}
return cached
}
override fun override(provider: ReactNativeFeatureFlagsProvider) =
ReactNativeFeatureFlagsCxxInterop.override(provider as Any)
override fun dangerouslyReset() = ReactNativeFeatureFlagsCxxInterop.dangerouslyReset()
}

Просмотреть файл

@ -1,36 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<c2e41ac8c3d9471b4cb79f6147cc2bf2>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
package com.facebook.react.internal.featureflags
import com.facebook.proguard.annotations.DoNotStrip
import com.facebook.soloader.SoLoader
@DoNotStrip
object ReactNativeFeatureFlagsCxxInterop {
init {
SoLoader.loadLibrary("reactfeatureflagsjni")
}
@DoNotStrip @JvmStatic external fun commonTestFlag(): Boolean
@DoNotStrip @JvmStatic external fun override(provider: Any)
@DoNotStrip @JvmStatic external fun dangerouslyReset()
}

Просмотреть файл

@ -1,27 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<aa1eaeee7b715e5b1d3cbcf9b7a7062e>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
package com.facebook.react.internal.featureflags
open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvider {
// We could use JNI to get the defaults from C++,
// but that is more expensive than just duplicating the defaults here.
override fun commonTestFlag(): Boolean = false
}

Просмотреть файл

@ -1,14 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.internal.featureflags
object ReactNativeFeatureFlagsForTests {
fun setUp() {
ReactNativeFeatureFlags.setAccessorProvider({ ReactNativeFeatureFlagsLocalAccessor() })
}
}

Просмотреть файл

@ -1,52 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8bbd7e8cc2c50cfbf44ba6671d095f23>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
package com.facebook.react.internal.featureflags
class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAccessor {
private var currentProvider: ReactNativeFeatureFlagsProvider = ReactNativeFeatureFlagsDefaults()
private val accessedFeatureFlags = mutableSetOf<String>()
private var commonTestFlagCache: Boolean? = null
override fun commonTestFlag(): Boolean {
var cached = commonTestFlagCache
if (cached == null) {
cached = currentProvider.commonTestFlag()
accessedFeatureFlags.add("commonTestFlag")
commonTestFlagCache = cached
}
return cached
}
override fun override(provider: ReactNativeFeatureFlagsProvider) {
if (accessedFeatureFlags.isNotEmpty()) {
val accessedFeatureFlagsStr = accessedFeatureFlags.joinToString(separator = ", ") { it }
throw IllegalStateException(
"Feature flags were accessed before being overridden: $accessedFeatureFlagsStr")
}
currentProvider = provider
}
override fun dangerouslyReset() {
// We don't need to do anything here because `ReactNativeFeatureFlags` will
// just create a new instance of this class.
}
}

Просмотреть файл

@ -1,24 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<babb2b7b32c88b1767ac53ae97dddf10>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
package com.facebook.react.internal.featureflags
interface ReactNativeFeatureFlagsProvider {
fun commonTestFlag(): Boolean
}

Просмотреть файл

@ -70,7 +70,6 @@ add_react_common_subdir(hermes/inspector-modern)
add_react_common_subdir(react/renderer/runtimescheduler)
add_react_common_subdir(react/debug)
add_react_common_subdir(react/config)
add_react_common_subdir(react/featureflags)
add_react_common_subdir(react/renderer/animations)
add_react_common_subdir(react/renderer/attributedstring)
add_react_common_subdir(react/renderer/componentregistry)
@ -119,7 +118,6 @@ add_react_android_subdir(src/main/jni/react/uimanager)
add_react_android_subdir(src/main/jni/react/mapbuffer)
add_react_android_subdir(src/main/jni/react/reactnativeblob)
add_react_android_subdir(src/main/jni/react/fabric)
add_react_android_subdir(src/main/jni/react/featureflags)
add_react_android_subdir(src/main/jni/react/newarchdefaults)
add_react_android_subdir(src/main/jni/react/hermes/reactexecutor)
add_react_android_subdir(src/main/jni/react/hermes/instrumentation/)

Просмотреть файл

@ -26,7 +26,6 @@ target_link_libraries(
mapbufferjni
react_codegen_rncore
react_debug
react_featureflags
react_render_animations
react_render_attributedstring
react_render_componentregistry

Просмотреть файл

@ -1,34 +0,0 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
file(GLOB featureflagsjni_SRCS CONFIGURE_DEPENDS *.cpp)
add_library(
featureflagsjni
SHARED
${featureflagsjni_SRCS}
)
target_include_directories(featureflagsjni PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(
featureflagsjni
fb
fbjni
react_featureflags
reactnativejni
)
target_compile_options(
featureflagsjni
PRIVATE
-DLOG_TAG=\"ReactNative\"
-fexceptions
-frtti
-std=c++20
-Wall
)

Просмотреть файл

@ -1,54 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ad6d2d1c24334995ba197c7cc0a74dc9>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#include "JReactNativeFeatureFlagsCxxInterop.h"
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/featureflags/ReactNativeFeatureFlagsProviderHolder.h>
namespace facebook::react {
bool JReactNativeFeatureFlagsCxxInterop::commonTestFlag(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::commonTestFlag();
}
void JReactNativeFeatureFlagsCxxInterop::override(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/,
jni::alias_ref<jobject> provider) {
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsProviderHolder>(provider));
}
void JReactNativeFeatureFlagsCxxInterop::dangerouslyReset(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
ReactNativeFeatureFlags::dangerouslyReset();
}
void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
javaClassLocal()->registerNatives({
makeNativeMethod(
"override", JReactNativeFeatureFlagsCxxInterop::override),
makeNativeMethod("dangerouslyReset", JReactNativeFeatureFlagsCxxInterop::dangerouslyReset),
makeNativeMethod(
"commonTestFlag",
JReactNativeFeatureFlagsCxxInterop::commonTestFlag),
});
}
} // namespace facebook::react

Просмотреть файл

@ -1,46 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<c759720f6c5f9b884f3eee8f3c104526>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#pragma once
#include <fbjni/fbjni.h>
#include <jni.h>
namespace facebook::react {
class JReactNativeFeatureFlagsCxxInterop
: public jni::JavaClass<JReactNativeFeatureFlagsCxxInterop> {
public:
constexpr static auto kJavaDescriptor =
"Lcom/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop;";
static bool commonTestFlag(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static void override(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>,
jni::alias_ref<jobject> provider);
static void dangerouslyReset(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static void registerNatives();
};
} // namespace facebook::react

Просмотреть файл

@ -1,16 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <fbjni/fbjni.h>
#include "JReactNativeFeatureFlagsCxxInterop.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
return facebook::jni::initialize(vm, [] {
facebook::react::JReactNativeFeatureFlagsCxxInterop::registerNatives();
});
}

Просмотреть файл

@ -1,32 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7a019bd967a22f93cd9e2e0ddb5201e3>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#include "ReactNativeFeatureFlagsProviderHolder.h"
namespace facebook::react {
bool ReactNativeFeatureFlagsProviderHolder::commonTestFlag() {
static const auto method =
facebook::jni::findClassStatic(
"com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider")
->getMethod<jboolean()>("commonTestFlag");
return method(javaProvider_);
}
} // namespace facebook::react

Просмотреть файл

@ -1,44 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<9a2d162cbd83f3b5122d0eb86f6f9177>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#pragma once
#include <fbjni/fbjni.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
namespace facebook::react {
/**
* Implementation of ReactNativeFeatureFlagsProvider that wraps a
* ReactNativeFeatureFlagsProvider Java object.
*/
class ReactNativeFeatureFlagsProviderHolder
: public ReactNativeFeatureFlagsProvider {
public:
explicit ReactNativeFeatureFlagsProviderHolder(
jni::alias_ref<jobject> javaProvider)
: javaProvider_(make_global(javaProvider)){};
bool commonTestFlag() override;
private:
jni::global_ref<jobject> javaProvider_;
};
} // namespace facebook::react

Просмотреть файл

@ -17,7 +17,6 @@ target_include_directories(react_newarchdefaults PUBLIC .)
target_link_libraries(react_newarchdefaults
fbjni
fabricjni
featureflagsjni
react_nativemodule_core
react_codegen_rncore
react_cxxreactpackage

Просмотреть файл

@ -23,7 +23,6 @@ target_include_directories(rninstance PUBLIC .)
target_link_libraries(
rninstance
fabricjni
featureflagsjni
turbomodulejsijni
fb
jsi

Просмотреть файл

@ -1,20 +0,0 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
add_compile_options(
-fexceptions
-frtti
-std=c++20
-Wall
-Wpedantic
-DLOG_TAG=\"ReactNative\")
file(GLOB react_featureflags_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_featureflags SHARED ${react_featureflags_SRC})
target_include_directories(react_featureflags PUBLIC ${REACT_COMMON_DIR})

Просмотреть файл

@ -1,44 +0,0 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end
header_search_paths = []
if ENV['USE_FRAMEWORKS']
header_search_paths << "\"$(PODS_TARGET_SRCROOT)/../..\"" # this is needed to allow the feature flags access its own files
end
Pod::Spec.new do |s|
s.name = "React-featureflags"
s.version = version
s.summary = "React Native internal feature flags"
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = "*.{cpp,h}"
s.header_dir = "react/featureflags"
s.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
"DEFINES_MODULE" => "YES" }
if ENV['USE_FRAMEWORKS']
s.module_name = "React_featureflags"
s.header_mappings_dir = "../.."
end
end

Просмотреть файл

@ -1,46 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<85960128b845159e7de70d0e85910dd9>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#include "ReactNativeFeatureFlags.h"
namespace facebook::react {
bool ReactNativeFeatureFlags::commonTestFlag() {
return getAccessor().commonTestFlag();
}
void ReactNativeFeatureFlags::override(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider) {
getAccessor().override(std::move(provider));
}
void ReactNativeFeatureFlags::dangerouslyReset() {
getAccessor(true);
}
ReactNativeFeatureFlagsAccessor& ReactNativeFeatureFlags::getAccessor(
bool reset) {
static std::unique_ptr<ReactNativeFeatureFlagsAccessor> accessor;
if (accessor == nullptr || reset) {
accessor = std::make_unique<ReactNativeFeatureFlagsAccessor>();
}
return *accessor;
}
} // namespace facebook::react

Просмотреть файл

@ -1,80 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<a4d59ac4d6a845349ffff6ba463fdf80>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#pragma once
#include <react/featureflags/ReactNativeFeatureFlagsAccessor.h>
#include <react/featureflags/ReactNativeFeatureFlagsProvider.h>
#include <memory>
namespace facebook::react {
/**
* This class provides access to internal React Native feature flags.
*
* All the methods are thread-safe if you handle `override` correctly.
*/
class ReactNativeFeatureFlags {
public:
/**
* Common flag for testing. Do NOT modify.
*/
static bool commonTestFlag();
/**
* Overrides the feature flags with the ones provided by the given provider
* (generally one that extends `ReactNativeFeatureFlagsDefaults`).
*
* This method must be called before you initialize the React Native runtime.
*
* @example
*
* ```
* class MyReactNativeFeatureFlags : public ReactNativeFeatureFlagsDefaults {
* public:
* bool someFlag() override;
* };
*
* ReactNativeFeatureFlags.override(
* std::make_unique<MyReactNativeFeatureFlags>());
* ```
*/
static void override(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider);
/**
* Removes the overridden feature flags and makes the API return default
* values again.
*
* This is **dangerous**. Use it only if you really understand the
* implications of this method.
*
* This should only be called if you destroy the React Native runtime and
* need to create a new one with different overrides. In that case,
* call `dangerouslyReset` after destroying the runtime and `override` again
* before initializing the new one.
*/
static void dangerouslyReset();
private:
ReactNativeFeatureFlags() = delete;
static ReactNativeFeatureFlagsAccessor& getAccessor(bool reset = false);
};
} // namespace facebook::react

Просмотреть файл

@ -1,69 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7f8b2ae5c0b18aceeaac0ee60e53bdbb>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#include <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
#include <algorithm>
#include <sstream>
#include <stdexcept>
#include "ReactNativeFeatureFlags.h"
namespace facebook::react {
ReactNativeFeatureFlagsAccessor::ReactNativeFeatureFlagsAccessor()
: currentProvider_(std::make_unique<ReactNativeFeatureFlagsDefaults>()) {}
bool ReactNativeFeatureFlagsAccessor::commonTestFlag() {
if (!commonTestFlag_.has_value()) {
// Mark the flag as accessed.
static const char* flagName = "commonTestFlag";
if (std::find(
accessedFeatureFlags_.begin(),
accessedFeatureFlags_.end(),
flagName) == accessedFeatureFlags_.end()) {
accessedFeatureFlags_.push_back(flagName);
}
commonTestFlag_.emplace(currentProvider_->commonTestFlag());
}
return commonTestFlag_.value();
}
void ReactNativeFeatureFlagsAccessor::override(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider) {
if (!accessedFeatureFlags_.empty()) {
std::ostringstream featureFlagListBuilder;
for (const auto& featureFlagName : accessedFeatureFlags_) {
featureFlagListBuilder << featureFlagName << ", ";
}
std::string accessedFeatureFlagNames = featureFlagListBuilder.str();
if (!accessedFeatureFlagNames.empty()) {
accessedFeatureFlagNames = accessedFeatureFlagNames.substr(
0, accessedFeatureFlagNames.size() - 2);
}
throw std::runtime_error(
"Feature flags were accessed before being overridden: " +
accessedFeatureFlagNames);
}
currentProvider_ = std::move(provider);
}
} // namespace facebook::react

Просмотреть файл

@ -1,44 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<3fa0171b372cf6aae150b2ec159fc41e>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#pragma once
#include <react/featureflags/ReactNativeFeatureFlagsProvider.h>
#include <memory>
#include <optional>
#include <vector>
namespace facebook::react {
class ReactNativeFeatureFlagsAccessor {
public:
ReactNativeFeatureFlagsAccessor();
bool commonTestFlag();
void override(std::unique_ptr<ReactNativeFeatureFlagsProvider> provider);
private:
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
std::vector<const char*> accessedFeatureFlags_;
std::optional<bool> commonTestFlag_;
};
} // namespace facebook::react

Просмотреть файл

@ -1,35 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<76033e9fb87174da88e0ee922df28701>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#pragma once
#include <react/featureflags/ReactNativeFeatureFlagsProvider.h>
namespace facebook::react {
class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
public:
ReactNativeFeatureFlagsDefaults() = default;
bool commonTestFlag() override {
return false;
}
};
} // namespace facebook::react

Просмотреть файл

@ -1,31 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<20dfc971dddc23a6d0cc55938b0d65b7>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#pragma once
namespace facebook::react {
class ReactNativeFeatureFlagsProvider {
public:
virtual ~ReactNativeFeatureFlagsProvider() = default;
virtual bool commonTestFlag() = 0;
};
} // namespace facebook::react

Просмотреть файл

@ -1,101 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
#include <stdexcept>
namespace facebook::react {
uint overrideAccessCount = 0;
class ReactNativeFeatureFlagsTestOverrides
: public ReactNativeFeatureFlagsDefaults {
public:
bool commonTestFlag() override {
overrideAccessCount++;
return true;
}
};
class ReactNativeFeatureFlagsTest : public testing::Test {
protected:
void SetUp() override {
overrideAccessCount = 0;
}
};
TEST_F(ReactNativeFeatureFlagsTest, providesDefaults) {
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), false);
}
TEST_F(ReactNativeFeatureFlagsTest, providesOverriddenValues) {
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsTestOverrides>());
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), true);
}
TEST_F(ReactNativeFeatureFlagsTest, preventsOverridingAfterAccess) {
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), false);
try {
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsTestOverrides>());
FAIL()
<< "Expected ReactNativeFeatureFlags::override() to throw an exception";
} catch (const std::runtime_error& e) {
EXPECT_STREQ(
"Feature flags were accessed before being overridden: commonTestFlag",
e.what());
}
// Overrides shouldn't be applied after they've been accessed
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), false);
}
TEST_F(ReactNativeFeatureFlagsTest, cachesValuesFromOverride) {
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsTestOverrides>());
EXPECT_EQ(overrideAccessCount, 0);
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), true);
EXPECT_EQ(overrideAccessCount, 1);
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), true);
EXPECT_EQ(overrideAccessCount, 1);
}
TEST_F(
ReactNativeFeatureFlagsTest,
providesDefaulValuesAgainWhenResettingAfterAnOverride) {
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsTestOverrides>());
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), true);
ReactNativeFeatureFlags::dangerouslyReset();
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), false);
}
TEST_F(ReactNativeFeatureFlagsTest, allowsOverridingAgainAfterReset) {
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsTestOverrides>());
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), true);
ReactNativeFeatureFlags::dangerouslyReset();
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsTestOverrides>());
EXPECT_EQ(ReactNativeFeatureFlags::commonTestFlag(), true);
}
} // namespace facebook::react

Просмотреть файл

@ -1,43 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f80c7362c3d377edfcbd5cc0642c2464>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#include "NativeReactNativeFeatureFlags.h"
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include "Plugins.h"
std::shared_ptr<facebook::react::TurboModule>
NativeReactNativeFeatureFlagsModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativeReactNativeFeatureFlags>(
std::move(jsInvoker));
}
namespace facebook::react {
NativeReactNativeFeatureFlags::NativeReactNativeFeatureFlags(
std::shared_ptr<CallInvoker> jsInvoker)
: NativeReactNativeFeatureFlagsCxxSpec(std::move(jsInvoker)) {}
bool NativeReactNativeFeatureFlags::commonTestFlag(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::commonTestFlag();
}
} // namespace facebook::react

Просмотреть файл

@ -1,36 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<18a3543b75c44e00bdf73ca2f12d230c>>
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
#pragma once
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
namespace facebook::react {
class NativeReactNativeFeatureFlags
: public NativeReactNativeFeatureFlagsCxxSpec<
NativeReactNativeFeatureFlags>,
std::enable_shared_from_this<NativeReactNativeFeatureFlags> {
public:
NativeReactNativeFeatureFlags(std::shared_ptr<CallInvoker> jsInvoker);
bool commonTestFlag(jsi::Runtime& runtime);
};
} // namespace facebook::react

Просмотреть файл

@ -30,7 +30,6 @@ target_link_libraries(
bridgeless
jserrorhandler
fabricjni
featureflagsjni
turbomodulejsijni
fb
jsi

Просмотреть файл

@ -89,9 +89,7 @@
"types"
],
"scripts": {
"prepack": "cp ../../README.md .",
"featureflags-check": "node ./scripts/featureflags/update.js --verify-unchanged",
"featureflags-update": "node ./scripts/featureflags/update.js"
"prepack": "cp ../../README.md ."
},
"peerDependencies": {
"react": "18.2.0"

Просмотреть файл

@ -556,7 +556,6 @@ class CodegenUtilsTests < Test::Unit::TestCase
'React-Fabric': [],
'React-FabricImage': [],
'React-utils': [],
'React-featureflags': [],
'React-debug': [],
'React-rendererdebug': [],
})
@ -570,14 +569,13 @@ class CodegenUtilsTests < Test::Unit::TestCase
specs = get_podspec_no_fabric_no_script()
specs["pod_target_xcconfig"]["FRAMEWORK_SEARCH_PATHS"].concat([])
specs["pod_target_xcconfig"]["HEADER_SEARCH_PATHS"].concat(" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-featureflags/React_featureflags.framework/Headers\"")
specs["pod_target_xcconfig"]["HEADER_SEARCH_PATHS"].concat(" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers\"")
specs[:dependencies].merge!({
'React-graphics': [],
'React-Fabric': [],
'React-FabricImage': [],
'React-utils': [],
'React-featureflags': [],
'React-debug': [],
'React-rendererdebug': [],
})

Просмотреть файл

@ -151,7 +151,7 @@ class NewArchitectureTests < Test::Unit::TestCase
folly_compiler_flags = folly_config[:compiler_flags]
assert_equal(spec.compiler_flags, NewArchitectureHelper.folly_compiler_flags)
assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-featureflags/React_featureflags.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-ImageManager/React_ImageManager.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers\"")
assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-ImageManager/React_ImageManager.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers\"")
assert_equal(spec.pod_target_xcconfig["CLANG_CXX_LANGUAGE_STANDARD"], "c++20")
assert_equal(spec.pod_target_xcconfig["OTHER_CPLUSPLUSFLAGS"], "$(inherited) -DRCT_NEW_ARCH_ENABLED=1 "+ folly_compiler_flags)
assert_equal(
@ -171,7 +171,6 @@ class NewArchitectureTests < Test::Unit::TestCase
{ :dependency_name => "React-Fabric" },
{ :dependency_name => "React-graphics" },
{ :dependency_name => "React-utils" },
{ :dependency_name => "React-featureflags" },
{ :dependency_name => "React-debug" },
{ :dependency_name => "React-ImageManager" },
{ :dependency_name => "React-rendererdebug" },
@ -194,7 +193,7 @@ class NewArchitectureTests < Test::Unit::TestCase
# Assert
assert_equal(Helpers::Constants.folly_config[:compiler_flags], "#{NewArchitectureHelper.folly_compiler_flags}")
assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "#{other_flags} \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-featureflags/React_featureflags.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-ImageManager/React_ImageManager.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers\"")
assert_equal(spec.pod_target_xcconfig["HEADER_SEARCH_PATHS"], "#{other_flags} \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Private/Yoga\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-FabricImage/React_FabricImage.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-RCTFabric/RCTFabric.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-utils/React_utils.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-debug/React_debug.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-ImageManager/React_ImageManager.framework/Headers\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-rendererdebug/React_rendererdebug.framework/Headers\"")
assert_equal(spec.pod_target_xcconfig["CLANG_CXX_LANGUAGE_STANDARD"], "c++20")
assert_equal(
spec.dependencies,
@ -213,7 +212,6 @@ class NewArchitectureTests < Test::Unit::TestCase
{ :dependency_name => "React-Fabric" },
{ :dependency_name => "React-graphics" },
{ :dependency_name => "React-utils" },
{ :dependency_name => "React-featureflags" },
{ :dependency_name => "React-debug" },
{ :dependency_name => "React-ImageManager" },
{ :dependency_name => "React-rendererdebug" },

Просмотреть файл

@ -101,7 +101,6 @@ class CodegenUtils
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-debug", "React_debug", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-rendererdebug", "React_rendererdebug", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-utils", "React_utils", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-featureflags", "React_featureflags", []))
.each { |search_path|
header_search_paths << "\"#{search_path}\""
}
@ -141,7 +140,6 @@ class CodegenUtils
'React-FabricImage': [],
'React-debug': [],
'React-utils': [],
'React-featureflags': [],
}
}

Просмотреть файл

@ -90,7 +90,6 @@ class NewArchitectureHelper
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-NativeModulesApple", "React_NativeModulesApple", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-RCTFabric", "RCTFabric", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-utils", "React_utils", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-featureflags", "React_featureflags", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-debug", "React_debug", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-ImageManager", "React_ImageManager", []))
.concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-rendererdebug", "React_rendererdebug", []))
@ -125,7 +124,6 @@ class NewArchitectureHelper
spec.dependency "React-Fabric"
spec.dependency "React-graphics"
spec.dependency "React-utils"
spec.dependency "React-featureflags"
spec.dependency "React-debug"
spec.dependency "React-ImageManager"
spec.dependency "React-rendererdebug"

Просмотреть файл

@ -1,146 +0,0 @@
# Feature Flags
Feature flags are values that determine the behavior of specific parts of React
Native. This directory contains the configuration for those values, and scripts
to generate files for different languages to access and customize them.
There are 2 types of feature flags:
* Common: can be accessed from any language and they provide consistent values
everywhere.
* JS-only: they can only be accessed and customized from JavaScript.
## Definition
The source of truth for the definition of the flags is the file `ReactNativeFeatureFlags.json`
in this directory. That JSON file should have the following structure:
```flow
type Config = {
common: FeatureFlagsList,
jsOnly: FeatureFlagsList,
};
type FeatureFlagsList = {
[flagName: string]: {
description: string,
defaultValue: boolean | number | string,
},
};
```
Example:
```json
{
"common": {
"enableMicrotasks": {
"description": "Enable the use of microtasks in the JS runtime.",
"defaultValue": false
}
},
"jsOnly": {
"enableAccessToHostTreeInFabric": {
"description": "Enables access to the host tree in Fabric using DOM-compatible APIs.",
"defaultValue": false
}
}
}
```
After any changes to this definitions, the code that provides access to them
must be regenerated executing the `update` script in this directory.
## Access
### C++ / Objective-C
```c++
#include <react/featureflags/ReactNativeFeatureFlags.h>
if (ReactNativeFeatureFlags::enableMicrotasks()) {
// do something
}
```
### Kotlin
```kotlin
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
fun someMethod() {
if (ReactNativeFeatureFlags.enableMicrotasks()) {
// do something
}
}
```
### JavaScript
```javascript
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
if (ReactNativeFeatureFlags.enableMicrotasks()) {
// Native flag
}
if (ReactNativeFeatureFlags.enableAccessToHostTreeInFabric()) {
// JS-only flag
}
```
## Customization
### C++/Objective-C
```c++
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
class CustomReactNativeFeatureFlags : public ReactNativeFeatureFlagsDefaults {
public:
CustomReactNativeFeatureFlags();
bool enableMicrotasks() override {
return true;
}
}
ReactNativeFeatureFlags::override(std::make_unique<CustomReactNativeFeatureFlags>());
```
### Kotlin
```kotlin
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsDefaults
fun overrideFeatureFlags() {
ReactNativeFeatureFlags.override(object : ReactNativeFeatureFlagsDefaults() {
override fun useMicrotasks(): Boolean = true
})
}
```
### JavaScript
```javascript
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
ReactNativeFeatureFlags.override({
enableAccessToHostTreeInFabric: () => true,
});
```
## Architecture
The architecture of this feature flags system can be described as follows:
* A shared C++ core, where we provide access to the flags and allow
customizations.
* A Kotlin/Java interface that allows accessing and customizing the values in
the C++ core (via JNI).
* A JavaScript interface that allows accessing the common values (via a native
module) and accessing and customizing the JS-only values.
![Diagram of the architecture of feature flags in React Native](./assets/react-native-feature-flags-architecture.excalidraw-embedded.png)
_This image has an embedded [Excalidraw](https://www.excalidraw.com) diagram,
so you can upload it there if you need to make further modifications._

Просмотреть файл

@ -1,14 +0,0 @@
{
"common": {
"commonTestFlag": {
"description": "Common flag for testing. Do NOT modify.",
"defaultValue": false
}
},
"jsOnly": {
"jsOnlyTestFlag": {
"description": "JS-only flag for testing. Do NOT modify.",
"defaultValue": false
}
}
}

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.0 MiB

Просмотреть файл

@ -1,68 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const JReactNativeFeatureFlagsCxxInteropCPP = require('./templates/android/JReactNativeFeatureFlagsCxxInterop.cpp-template');
const JReactNativeFeatureFlagsCxxInteropH = require('./templates/android/JReactNativeFeatureFlagsCxxInterop.h-template');
const ReactNativeFeatureFlagsKt = require('./templates/android/ReactNativeFeatureFlags.kt-template');
const ReactNativeFeatureFlagsCxxAccessorKt = require('./templates/android/ReactNativeFeatureFlagsCxxAccessor.kt-template');
const ReactNativeFeatureFlagsCxxInteropKt = require('./templates/android/ReactNativeFeatureFlagsCxxInterop.kt-template');
const ReactNativeFeatureFlagsDefaultsKt = require('./templates/android/ReactNativeFeatureFlagsDefaults.kt-template');
const ReactNativeFeatureFlagsLocalAccessorKt = require('./templates/android/ReactNativeFeatureFlagsLocalAccessor.kt-template');
const ReactNativeFeatureFlagsProviderKt = require('./templates/android/ReactNativeFeatureFlagsProvider.kt-template');
const ReactNativeFeatureFlagsProviderHolderCPP = require('./templates/android/ReactNativeFeatureFlagsProviderHolder.cpp-template');
const ReactNativeFeatureFlagsProviderHolderH = require('./templates/android/ReactNativeFeatureFlagsProviderHolder.h-template');
const path = require('path');
module.exports = function generateandroidModules(
generatorConfig,
featureFlagsConfig,
) {
return {
[path.join(generatorConfig.androidPath, 'ReactNativeFeatureFlags.kt')]:
ReactNativeFeatureFlagsKt(featureFlagsConfig),
[path.join(
generatorConfig.androidPath,
'ReactNativeFeatureFlagsCxxAccessor.kt',
)]: ReactNativeFeatureFlagsCxxAccessorKt(featureFlagsConfig),
[path.join(
generatorConfig.androidPath,
'ReactNativeFeatureFlagsLocalAccessor.kt',
)]: ReactNativeFeatureFlagsLocalAccessorKt(featureFlagsConfig),
[path.join(
generatorConfig.androidPath,
'ReactNativeFeatureFlagsCxxInterop.kt',
)]: ReactNativeFeatureFlagsCxxInteropKt(featureFlagsConfig),
[path.join(
generatorConfig.androidPath,
'ReactNativeFeatureFlagsDefaults.kt',
)]: ReactNativeFeatureFlagsDefaultsKt(featureFlagsConfig),
[path.join(
generatorConfig.androidPath,
'ReactNativeFeatureFlagsProvider.kt',
)]: ReactNativeFeatureFlagsProviderKt(featureFlagsConfig),
[path.join(
generatorConfig.androidJniPath,
'ReactNativeFeatureFlagsProviderHolder.h',
)]: ReactNativeFeatureFlagsProviderHolderH(featureFlagsConfig),
[path.join(
generatorConfig.androidJniPath,
'ReactNativeFeatureFlagsProviderHolder.cpp',
)]: ReactNativeFeatureFlagsProviderHolderCPP(featureFlagsConfig),
[path.join(
generatorConfig.androidJniPath,
'JReactNativeFeatureFlagsCxxInterop.h',
)]: JReactNativeFeatureFlagsCxxInteropH(featureFlagsConfig),
[path.join(
generatorConfig.androidJniPath,
'JReactNativeFeatureFlagsCxxInterop.cpp',
)]: JReactNativeFeatureFlagsCxxInteropCPP(featureFlagsConfig),
};
};

Просмотреть файл

@ -1,46 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const ReactNativeFeatureFlagsCPP = require('./templates/common-cxx/ReactNativeFeatureFlags.cpp-template');
const ReactNativeFeatureFlagsH = require('./templates/common-cxx/ReactNativeFeatureFlags.h-template');
const ReactNativeFeatureFlagsAccessorCPP = require('./templates/common-cxx/ReactNativeFeatureFlagsAccessor.cpp-template');
const ReactNativeFeatureFlagsAccessorH = require('./templates/common-cxx/ReactNativeFeatureFlagsAccessor.h-template');
const ReactNativeFeatureFlagsDefaultsH = require('./templates/common-cxx/ReactNativeFeatureFlagsDefaults.h-template');
const ReactNativeFeatureFlagsProviderH = require('./templates/common-cxx/ReactNativeFeatureFlagsProvider.h-template');
const path = require('path');
module.exports = function generateCommonCxxModules(
generatorConfig,
featureFlagsConfig,
) {
return {
[path.join(generatorConfig.commonCxxPath, 'ReactNativeFeatureFlags.h')]:
ReactNativeFeatureFlagsH(featureFlagsConfig),
[path.join(generatorConfig.commonCxxPath, 'ReactNativeFeatureFlags.cpp')]:
ReactNativeFeatureFlagsCPP(featureFlagsConfig),
[path.join(
generatorConfig.commonCxxPath,
'ReactNativeFeatureFlagsAccessor.h',
)]: ReactNativeFeatureFlagsAccessorH(featureFlagsConfig),
[path.join(
generatorConfig.commonCxxPath,
'ReactNativeFeatureFlagsAccessor.cpp',
)]: ReactNativeFeatureFlagsAccessorCPP(featureFlagsConfig),
[path.join(
generatorConfig.commonCxxPath,
'ReactNativeFeatureFlagsDefaults.h',
)]: ReactNativeFeatureFlagsDefaultsH(featureFlagsConfig),
[path.join(
generatorConfig.commonCxxPath,
'ReactNativeFeatureFlagsProvider.h',
)]: ReactNativeFeatureFlagsProviderH(featureFlagsConfig),
};
};

Просмотреть файл

@ -1,82 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
const generateAndroidModules = require('./generateAndroidModules');
const generateCommonCxxModules = require('./generateCommonCxxModules');
const generateJavaScriptModules = require('./generateJavaScriptModules');
const fs = require('fs');
module.exports = function generateFiles(generatorConfig, generatorOptions) {
const userDefinedFeatureFlagsConfig = JSON.parse(
fs.readFileSync(generatorConfig.configPath, 'utf8'),
);
const featureFlagsConfig = Object.assign(
{jsOnly: {}, common: {}},
userDefinedFeatureFlagsConfig,
);
fs.mkdirSync(generatorConfig.jsPath, {recursive: true});
fs.mkdirSync(generatorConfig.commonCxxPath, {recursive: true});
fs.mkdirSync(generatorConfig.commonNativeModuleCxxPath, {recursive: true});
fs.mkdirSync(generatorConfig.androidPath, {recursive: true});
fs.mkdirSync(generatorConfig.androidJniPath, {recursive: true});
const jsModules = generateJavaScriptModules(
generatorConfig,
featureFlagsConfig,
);
const commonCxxModules = generateCommonCxxModules(
generatorConfig,
featureFlagsConfig,
);
const androidModules = generateAndroidModules(
generatorConfig,
featureFlagsConfig,
);
const generatedFiles = {...jsModules, ...commonCxxModules, ...androidModules};
if (generatorOptions.verifyUnchanged) {
const existingModules = {};
for (const moduleName of Object.keys(generatedFiles)) {
const existingModule = fs.readFileSync(moduleName, 'utf8');
existingModules[moduleName] = existingModule;
}
const changedFiles = [];
for (const moduleName of Object.keys(generatedFiles)) {
const module = generatedFiles[moduleName];
const existingModule = existingModules[moduleName];
if (module !== existingModule) {
changedFiles.push(moduleName);
}
}
if (changedFiles.length > 0) {
const changedFilesStr = changedFiles
.map(changedFile => ' ' + changedFile)
.join('\n');
throw new Error(
`Detected changes in generated files for feature flags:\n${changedFilesStr}\n\n` +
'Please rerun `yarn featureflags-update` and commit the changes.',
);
}
return;
}
for (const [modulePath, moduleContents] of Object.entries(generatedFiles)) {
fs.writeFileSync(modulePath, moduleContents, 'utf8');
}
};

Просмотреть файл

@ -1,36 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const NativeReactNativeFeatureFlagsCPP = require('./templates/js/NativeReactNativeFeatureFlags.cpp-template');
const NativeReactNativeFeatureFlagsH = require('./templates/js/NativeReactNativeFeatureFlags.h-template');
const NativeReactNativeFeatureFlagsJS = require('./templates/js/NativeReactNativeFeatureFlags.js-template');
const ReactNativeFeatureFlagsJS = require('./templates/js/ReactNativeFeatureFlags.js-template');
const path = require('path');
module.exports = function generateCommonCxxModules(
generatorConfig,
featureFlagsConfig,
) {
return {
[path.join(generatorConfig.jsPath, 'ReactNativeFeatureFlags.js')]:
ReactNativeFeatureFlagsJS(featureFlagsConfig),
[path.join(generatorConfig.jsPath, 'NativeReactNativeFeatureFlags.js')]:
NativeReactNativeFeatureFlagsJS(featureFlagsConfig),
[path.join(
generatorConfig.commonNativeModuleCxxPath,
'NativeReactNativeFeatureFlags.h',
)]: NativeReactNativeFeatureFlagsH(featureFlagsConfig),
[path.join(
generatorConfig.commonNativeModuleCxxPath,
'NativeReactNativeFeatureFlags.cpp',
)]: NativeReactNativeFeatureFlagsCPP(featureFlagsConfig),
};
};

Просмотреть файл

@ -1,77 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#include "JReactNativeFeatureFlagsCxxInterop.h"
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/featureflags/ReactNativeFeatureFlagsProviderHolder.h>
namespace facebook::react {
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
`${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} JReactNativeFeatureFlagsCxxInterop::${flagName}(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::${flagName}();
}`,
)
.join('\n\n')}
void JReactNativeFeatureFlagsCxxInterop::override(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/,
jni::alias_ref<jobject> provider) {
ReactNativeFeatureFlags::override(
std::make_unique<ReactNativeFeatureFlagsProviderHolder>(provider));
}
void JReactNativeFeatureFlagsCxxInterop::dangerouslyReset(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
ReactNativeFeatureFlags::dangerouslyReset();
}
void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
javaClassLocal()->registerNatives({
makeNativeMethod(
"override", JReactNativeFeatureFlagsCxxInterop::override),
makeNativeMethod("dangerouslyReset", JReactNativeFeatureFlagsCxxInterop::dangerouslyReset),
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` makeNativeMethod(
"${flagName}",
JReactNativeFeatureFlagsCxxInterop::${flagName}),`,
)
.join('\n')}
});
}
} // namespace facebook::react
`);

Просмотреть файл

@ -1,64 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#pragma once
#include <fbjni/fbjni.h>
#include <jni.h>
namespace facebook::react {
class JReactNativeFeatureFlagsCxxInterop
: public jni::JavaClass<JReactNativeFeatureFlagsCxxInterop> {
public:
constexpr static auto kJavaDescriptor =
"Lcom/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop;";
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` static ${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ${flagName}(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);`,
)
.join('\n\n')}
static void override(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>,
jni::alias_ref<jobject> provider);
static void dangerouslyReset(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static void registerNatives();
};
} // namespace facebook::react
`);

Просмотреть файл

@ -1,91 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {DO_NOT_MODIFY_COMMENT} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
package com.facebook.react.internal.featureflags
/**
* This object provides access to internal React Native feature flags.
*
* All the methods are thread-safe if you handle \`override\` correctly.
*/
object ReactNativeFeatureFlags {
private var accessorProvider: () -> ReactNativeFeatureFlagsAccessor = { ReactNativeFeatureFlagsCxxAccessor() }
private var accessor: ReactNativeFeatureFlagsAccessor = accessorProvider()
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` /**
* ${flagConfig.description}
*/
fun ${flagName}() = accessor.${flagName}()`,
)
.join('\n\n')}
/**
* Overrides the feature flags with the ones provided by the given provider
* (generally one that extends \`ReactNativeFeatureFlagsDefaults\`).
*
* This method must be called before you initialize the React Native runtime.
*
* @example
*
* \`\`\`
* ReactNativeFeatureFlags.override(object : ReactNativeFeatureFlagsDefaults() {
* override fun someFlag(): Boolean = true // or a dynamic value
* })
* \`\`\`
*/
fun override(provider: ReactNativeFeatureFlagsProvider) = accessor.override(provider)
/**
* Removes the overridden feature flags and makes the API return default
* values again.
*
* This should only be called if you destroy the React Native runtime and
* need to create a new one with different overrides. In that case,
* call \`dangerouslyReset\` after destroying the runtime and \`override\`
* again before initializing the new one.
*/
fun dangerouslyReset() {
// This is necessary when the accessor interops with C++ and we need to
// remove the overrides set there.
accessor.dangerouslyReset()
// This discards the cached values and the overrides set in the JVM.
accessor = accessorProvider()
}
/**
* This is just used to replace the default ReactNativeFeatureFlagsCxxAccessor
* that uses JNI with a version that doesn't, to simplify testing.
*/
internal fun setAccessorProvider(newAccessorProvider: () -> ReactNativeFeatureFlagsAccessor) {
accessorProvider = newAccessorProvider
accessor = accessorProvider()
}
}
`);

Просмотреть файл

@ -1,60 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getKotlinTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
package com.facebook.react.internal.featureflags
class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccessor {
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` private var ${flagName}Cache: ${getKotlinTypeFromDefaultValue(
flagConfig.defaultValue,
)}? = null`,
)
.join('\n')}
${Object.entries(config.common)
.map(
([flagName, flagConfig]) => ` override fun ${flagName}(): Boolean {
var cached = ${flagName}Cache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.${flagName}()
${flagName}Cache = cached
}
return cached
}`,
)
.join('\n\n')}
override fun override(provider: ReactNativeFeatureFlagsProvider) =
ReactNativeFeatureFlagsCxxInterop.override(provider as Any)
override fun dangerouslyReset() = ReactNativeFeatureFlagsCxxInterop.dangerouslyReset()
}
`);

Просмотреть файл

@ -1,54 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getKotlinTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
package com.facebook.react.internal.featureflags
import com.facebook.proguard.annotations.DoNotStrip
import com.facebook.soloader.SoLoader
@DoNotStrip
object ReactNativeFeatureFlagsCxxInterop {
init {
SoLoader.loadLibrary("reactfeatureflagsjni")
}
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` @DoNotStrip @JvmStatic external fun ${flagName}(): ${getKotlinTypeFromDefaultValue(
flagConfig.defaultValue,
)}`,
)
.join('\n')}
@DoNotStrip @JvmStatic external fun override(provider: Any)
@DoNotStrip @JvmStatic external fun dangerouslyReset()
}
`);

Просмотреть файл

@ -1,45 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getKotlinTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
package com.facebook.react.internal.featureflags
open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvider {
// We could use JNI to get the defaults from C++,
// but that is more expensive than just duplicating the defaults here.
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` override fun ${flagName}(): ${getKotlinTypeFromDefaultValue(
flagConfig.defaultValue,
)} = ${JSON.stringify(flagConfig.defaultValue)}`,
)
.join('\n')}
}
`);

Просмотреть файл

@ -1,74 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getKotlinTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
package com.facebook.react.internal.featureflags
class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAccessor {
private var currentProvider: ReactNativeFeatureFlagsProvider = ReactNativeFeatureFlagsDefaults()
private val accessedFeatureFlags = mutableSetOf<String>()
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` private var ${flagName}Cache: ${getKotlinTypeFromDefaultValue(
flagConfig.defaultValue,
)}? = null`,
)
.join('\n')}
${Object.entries(config.common)
.map(
([flagName, flagConfig]) => ` override fun ${flagName}(): Boolean {
var cached = ${flagName}Cache
if (cached == null) {
cached = currentProvider.${flagName}()
accessedFeatureFlags.add("${flagName}")
${flagName}Cache = cached
}
return cached
}`,
)
.join('\n\n')}
override fun override(provider: ReactNativeFeatureFlagsProvider) {
if (accessedFeatureFlags.isNotEmpty()) {
val accessedFeatureFlagsStr = accessedFeatureFlags.joinToString(separator = ", ") { it }
throw IllegalStateException(
"Feature flags were accessed before being overridden: $accessedFeatureFlagsStr")
}
currentProvider = provider
}
override fun dangerouslyReset() {
// We don't need to do anything here because \`ReactNativeFeatureFlags\` will
// just create a new instance of this class.
}
}
`);

Просмотреть файл

@ -1,42 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getKotlinTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
package com.facebook.react.internal.featureflags
interface ReactNativeFeatureFlagsProvider {
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` fun ${flagName}(): ${getKotlinTypeFromDefaultValue(
flagConfig.defaultValue,
)}`,
)
.join('\n')}
}
`);

Просмотреть файл

@ -1,50 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#include "ReactNativeFeatureFlagsProviderHolder.h"
namespace facebook::react {
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
`${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ReactNativeFeatureFlagsProviderHolder::${flagName}() {
static const auto method =
facebook::jni::findClassStatic(
"com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider")
->getMethod<jboolean()>("${flagName}");
return method(javaProvider_);
}`,
)
.join('\n\n')}
} // namespace facebook::react
`);

Просмотреть файл

@ -1,62 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#pragma once
#include <fbjni/fbjni.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
namespace facebook::react {
/**
* Implementation of ReactNativeFeatureFlagsProvider that wraps a
* ReactNativeFeatureFlagsProvider Java object.
*/
class ReactNativeFeatureFlagsProviderHolder
: public ReactNativeFeatureFlagsProvider {
public:
explicit ReactNativeFeatureFlagsProviderHolder(
jni::alias_ref<jobject> javaProvider)
: javaProvider_(make_global(javaProvider)){};
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` ${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ${flagName}() override;`,
)
.join('\n')}
private:
jni::global_ref<jobject> javaProvider_;
};
} // namespace facebook::react
`);

Просмотреть файл

@ -1,64 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#include "ReactNativeFeatureFlags.h"
namespace facebook::react {
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
`${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ReactNativeFeatureFlags::${flagName}() {
return getAccessor().${flagName}();
}`,
)
.join('\n\n')}
void ReactNativeFeatureFlags::override(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider) {
getAccessor().override(std::move(provider));
}
void ReactNativeFeatureFlags::dangerouslyReset() {
getAccessor(true);
}
ReactNativeFeatureFlagsAccessor& ReactNativeFeatureFlags::getAccessor(
bool reset) {
static std::unique_ptr<ReactNativeFeatureFlagsAccessor> accessor;
if (accessor == nullptr || reset) {
accessor = std::make_unique<ReactNativeFeatureFlagsAccessor>();
}
return *accessor;
}
} // namespace facebook::react
`);

Просмотреть файл

@ -1,96 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#pragma once
#include <react/featureflags/ReactNativeFeatureFlagsAccessor.h>
#include <react/featureflags/ReactNativeFeatureFlagsProvider.h>
#include <memory>
namespace facebook::react {
/**
* This class provides access to internal React Native feature flags.
*
* All the methods are thread-safe if you handle \`override\` correctly.
*/
class ReactNativeFeatureFlags {
public:
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` /**
* ${flagConfig.description}
*/
static ${getCxxTypeFromDefaultValue(flagConfig.defaultValue)} ${flagName}();`,
)
.join('\n\n')}
/**
* Overrides the feature flags with the ones provided by the given provider
* (generally one that extends \`ReactNativeFeatureFlagsDefaults\`).
*
* This method must be called before you initialize the React Native runtime.
*
* @example
*
* \`\`\`
* class MyReactNativeFeatureFlags : public ReactNativeFeatureFlagsDefaults {
* public:
* bool someFlag() override;
* };
*
* ReactNativeFeatureFlags.override(
* std::make_unique<MyReactNativeFeatureFlags>());
* \`\`\`
*/
static void override(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider);
/**
* Removes the overridden feature flags and makes the API return default
* values again.
*
* This is **dangerous**. Use it only if you really understand the
* implications of this method.
*
* This should only be called if you destroy the React Native runtime and
* need to create a new one with different overrides. In that case,
* call \`dangerouslyReset\` after destroying the runtime and \`override\` again
* before initializing the new one.
*/
static void dangerouslyReset();
private:
ReactNativeFeatureFlags() = delete;
static ReactNativeFeatureFlagsAccessor& getAccessor(bool reset = false);
};
} // namespace facebook::react
`);

Просмотреть файл

@ -1,87 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#include <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
#include <algorithm>
#include <sstream>
#include <stdexcept>
#include "ReactNativeFeatureFlags.h"
namespace facebook::react {
ReactNativeFeatureFlagsAccessor::ReactNativeFeatureFlagsAccessor()
: currentProvider_(std::make_unique<ReactNativeFeatureFlagsDefaults>()) {}
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
`${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ReactNativeFeatureFlagsAccessor::${flagName}() {
if (!${flagName}_.has_value()) {
// Mark the flag as accessed.
static const char* flagName = "${flagName}";
if (std::find(
accessedFeatureFlags_.begin(),
accessedFeatureFlags_.end(),
flagName) == accessedFeatureFlags_.end()) {
accessedFeatureFlags_.push_back(flagName);
}
${flagName}_.emplace(currentProvider_->${flagName}());
}
return ${flagName}_.value();
}`,
)
.join('\n\n')}
void ReactNativeFeatureFlagsAccessor::override(
std::unique_ptr<ReactNativeFeatureFlagsProvider> provider) {
if (!accessedFeatureFlags_.empty()) {
std::ostringstream featureFlagListBuilder;
for (const auto& featureFlagName : accessedFeatureFlags_) {
featureFlagListBuilder << featureFlagName << ", ";
}
std::string accessedFeatureFlagNames = featureFlagListBuilder.str();
if (!accessedFeatureFlagNames.empty()) {
accessedFeatureFlagNames = accessedFeatureFlagNames.substr(
0, accessedFeatureFlagNames.size() - 2);
}
throw std::runtime_error(
"Feature flags were accessed before being overridden: " +
accessedFeatureFlagNames);
}
currentProvider_ = std::move(provider);
}
} // namespace facebook::react
`);

Просмотреть файл

@ -1,67 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#pragma once
#include <react/featureflags/ReactNativeFeatureFlagsProvider.h>
#include <memory>
#include <optional>
#include <vector>
namespace facebook::react {
class ReactNativeFeatureFlagsAccessor {
public:
ReactNativeFeatureFlagsAccessor();
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` ${getCxxTypeFromDefaultValue(flagConfig.defaultValue)} ${flagName}();`,
)
.join('\n')}
void override(std::unique_ptr<ReactNativeFeatureFlagsProvider> provider);
private:
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
std::vector<const char*> accessedFeatureFlags_;
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` std::optional<${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)}> ${flagName}_;`,
)
.join('\n')}
};
} // namespace facebook::react
`);

Просмотреть файл

@ -1,53 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#pragma once
#include <react/featureflags/ReactNativeFeatureFlagsProvider.h>
namespace facebook::react {
class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
public:
ReactNativeFeatureFlagsDefaults() = default;
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` ${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ${flagName}() override {
return ${JSON.stringify(flagConfig.defaultValue)};
}`,
)
.join('\n\n')}
};
} // namespace facebook::react
`);

Просмотреть файл

@ -1,49 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#pragma once
namespace facebook::react {
class ReactNativeFeatureFlagsProvider {
public:
virtual ~ReactNativeFeatureFlagsProvider() = default;
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` virtual ${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ${flagName}() = 0;`,
)
.join('\n')}
};
} // namespace facebook::react
`);

Просмотреть файл

@ -1,61 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#include "NativeReactNativeFeatureFlags.h"
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include "Plugins.h"
std::shared_ptr<facebook::react::TurboModule>
NativeReactNativeFeatureFlagsModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativeReactNativeFeatureFlags>(
std::move(jsInvoker));
}
namespace facebook::react {
NativeReactNativeFeatureFlags::NativeReactNativeFeatureFlags(
std::shared_ptr<CallInvoker> jsInvoker)
: NativeReactNativeFeatureFlagsCxxSpec(std::move(jsInvoker)) {}
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
`${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} NativeReactNativeFeatureFlags::${flagName}(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::${flagName}();
}`,
)
.join('\n\n')}
} // namespace facebook::react
`);

Просмотреть файл

@ -1,54 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {
DO_NOT_MODIFY_COMMENT,
getCxxTypeFromDefaultValue,
} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
*/
${DO_NOT_MODIFY_COMMENT}
#pragma once
#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
namespace facebook::react {
class NativeReactNativeFeatureFlags
: public NativeReactNativeFeatureFlagsCxxSpec<
NativeReactNativeFeatureFlags>,
std::enable_shared_from_this<NativeReactNativeFeatureFlags> {
public:
NativeReactNativeFeatureFlags(std::shared_ptr<CallInvoker> jsInvoker);
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` ${getCxxTypeFromDefaultValue(
flagConfig.defaultValue,
)} ${flagName}(jsi::Runtime& runtime);`,
)
.join('\n\n')}
};
} // namespace facebook::react
`);

Просмотреть файл

@ -1,46 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {DO_NOT_MODIFY_COMMENT} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
* @flow strict-local
*/
${DO_NOT_MODIFY_COMMENT}
import type {TurboModule} from '../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` +${flagName}?: () => ${typeof flagConfig.defaultValue};`,
)
.join('\n')}
}
const NativeReactNativeFeatureFlags: ?Spec = TurboModuleRegistry.get<Spec>(
'NativeReactNativeFeatureFlagsCxx',
);
export default NativeReactNativeFeatureFlags;
`);

Просмотреть файл

@ -1,85 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const {DO_NOT_MODIFY_COMMENT} = require('../../utils');
const signedsource = require('signedsource');
module.exports = config =>
signedsource.signFile(`/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${signedsource.getSigningToken()}
* @flow strict-local
*/
${DO_NOT_MODIFY_COMMENT}
import {
type Getter,
createJavaScriptFlagGetter,
createNativeFlagGetter,
setOverrides,
} from './ReactNativeFeatureFlagsBase';
export type ReactNativeFeatureFlagsJsOnly = {
${Object.entries(config.jsOnly)
.map(
([flagName, flagConfig]) =>
` ${flagName}: Getter<${typeof flagConfig.defaultValue}>,`,
)
.join('\n')}
};
export type ReactNativeFeatureFlagsJsOnlyOverrides = Partial<ReactNativeFeatureFlagsJsOnly>;
export type ReactNativeFeatureFlags = {
...ReactNativeFeatureFlagsJsOnly,
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
` ${flagName}: Getter<${typeof flagConfig.defaultValue}>,`,
)
.join('\n')}
}
${Object.entries(config.jsOnly)
.map(
([flagName, flagConfig]) =>
`/**
* ${flagConfig.description}
*/
export const ${flagName}: Getter<${typeof flagConfig.defaultValue}> = createJavaScriptFlagGetter('${flagName}', ${JSON.stringify(
flagConfig.defaultValue,
)});`,
)
.join('\n\n')}
${Object.entries(config.common)
.map(
([flagName, flagConfig]) =>
`/**
* ${flagConfig.description}
*/
export const ${flagName}: Getter<${typeof flagConfig.defaultValue}> = createNativeFlagGetter('${flagName}', ${JSON.stringify(
flagConfig.defaultValue,
)});`,
)
.join('\n')}
/**
* Overrides the feature flags with the provided methods.
* NOTE: Only JS-only flags can be overridden from JavaScript using this API.
*/
export const override = setOverrides;
`);

Просмотреть файл

@ -1,68 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
const generateFiles = require('./generateFiles');
const path = require('path');
const REACT_NATIVE_PACKAGE_ROOT = path.join(__dirname, '..', '..');
function update() {
generateFiles(
{
configPath: path.join(__dirname, 'ReactNativeFeatureFlags.json'),
jsPath: path.join(
REACT_NATIVE_PACKAGE_ROOT,
'src',
'private',
'featureflags',
),
commonCxxPath: path.join(
REACT_NATIVE_PACKAGE_ROOT,
'ReactCommon',
'react',
'featureflags',
),
commonNativeModuleCxxPath: path.join(
REACT_NATIVE_PACKAGE_ROOT,
'ReactCommon',
'react',
'nativemodule',
'featureflags',
),
androidPath: path.join(
REACT_NATIVE_PACKAGE_ROOT,
'ReactAndroid',
'src',
'main',
'java',
'com',
'facebook',
'react',
'internal',
'featureflags',
),
androidJniPath: path.join(
REACT_NATIVE_PACKAGE_ROOT,
'ReactAndroid',
'src',
'main',
'jni',
'react',
'featureflags',
),
},
{
verifyUnchanged: process.argv.includes('--verify-unchanged'),
},
);
}
if (require.main === module) {
update();
}

Просмотреть файл

@ -1,50 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
module.exports = {
getCxxTypeFromDefaultValue: defaultValue => {
switch (typeof defaultValue) {
case 'boolean':
return 'bool';
case 'number':
return 'int';
case 'string':
return 'std::string';
default:
throw new Error(
`Unsupported default value type: ${typeof defaultValue}`,
);
}
},
getKotlinTypeFromDefaultValue: defaultValue => {
switch (typeof defaultValue) {
case 'boolean':
return 'Boolean';
case 'number':
return 'Int';
case 'string':
return 'String';
default:
throw new Error(
`Unsupported default value type: ${typeof defaultValue}`,
);
}
},
DO_NOT_MODIFY_COMMENT: `/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/`,
};

Просмотреть файл

@ -124,7 +124,6 @@ def use_react_native! (
pod 'React-cxxreact', :path => "#{prefix}/ReactCommon/cxxreact"
pod 'React-debug', :path => "#{prefix}/ReactCommon/react/debug"
pod 'React-utils', :path => "#{prefix}/ReactCommon/react/utils"
pod 'React-featureflags', :path => "#{prefix}/ReactCommon/react/featureflags"
pod 'React-Mapbuffer', :path => "#{prefix}/ReactCommon"
pod 'React-jserrorhandler', :path => "#{prefix}/ReactCommon/jserrorhandler"
pod 'React-nativeconfig', :path => "#{prefix}/ReactCommon"

Просмотреть файл

@ -1,33 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ec82a5158f766de0467ab9a38e4ffb15>>
* @flow strict-local
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
import type {TurboModule} from '../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+commonTestFlag?: () => boolean;
}
const NativeReactNativeFeatureFlags: ?Spec = TurboModuleRegistry.get<Spec>(
'NativeReactNativeFeatureFlagsCxx',
);
export default NativeReactNativeFeatureFlags;

Просмотреть файл

@ -1,53 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<b554016876afbf53c25670806a5ff581>>
* @flow strict-local
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.json.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
import {
type Getter,
createJavaScriptFlagGetter,
createNativeFlagGetter,
setOverrides,
} from './ReactNativeFeatureFlagsBase';
export type ReactNativeFeatureFlagsJsOnly = {
jsOnlyTestFlag: Getter<boolean>,
};
export type ReactNativeFeatureFlagsJsOnlyOverrides = Partial<ReactNativeFeatureFlagsJsOnly>;
export type ReactNativeFeatureFlags = {
...ReactNativeFeatureFlagsJsOnly,
commonTestFlag: Getter<boolean>,
}
/**
* JS-only flag for testing. Do NOT modify.
*/
export const jsOnlyTestFlag: Getter<boolean> = createJavaScriptFlagGetter('jsOnlyTestFlag', false);
/**
* Common flag for testing. Do NOT modify.
*/
export const commonTestFlag: Getter<boolean> = createNativeFlagGetter('commonTestFlag', false);
/**
* Overrides the feature flags with the provided methods.
* NOTE: Only JS-only flags can be overridden from JavaScript using this API.
*/
export const override = setOverrides;

Просмотреть файл

@ -1,80 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {
ReactNativeFeatureFlagsJsOnly,
ReactNativeFeatureFlagsJsOnlyOverrides,
} from './ReactNativeFeatureFlags';
import NativeReactNativeFeatureFlags from './NativeReactNativeFeatureFlags';
const accessedFeatureFlags: Set<string> = new Set();
const overrides: ReactNativeFeatureFlagsJsOnlyOverrides = {};
export type Getter<T> = () => T;
function createGetter<T: boolean | number | string>(
configName: string,
customValueGetter: Getter<?T>,
defaultValue: T,
): Getter<T> {
let cachedValue: ?T;
return () => {
if (cachedValue == null) {
accessedFeatureFlags.add(configName);
cachedValue = customValueGetter() ?? defaultValue;
}
return cachedValue;
};
}
export function createJavaScriptFlagGetter<
K: $Keys<ReactNativeFeatureFlagsJsOnly>,
>(
configName: K,
defaultValue: ReturnType<ReactNativeFeatureFlagsJsOnly[K]>,
): Getter<ReturnType<ReactNativeFeatureFlagsJsOnly[K]>> {
return createGetter(
configName,
() => overrides[configName]?.(),
defaultValue,
);
}
type NativeFeatureFlags = $NonMaybeType<typeof NativeReactNativeFeatureFlags>;
export function createNativeFlagGetter<K: $Keys<NativeFeatureFlags>>(
configName: K,
defaultValue: ReturnType<$NonMaybeType<NativeFeatureFlags[K]>>,
): Getter<ReturnType<$NonMaybeType<NativeFeatureFlags[K]>>> {
return createGetter(
configName,
() => NativeReactNativeFeatureFlags?.[configName]?.(),
defaultValue,
);
}
export function getOverrides(): ?ReactNativeFeatureFlagsJsOnlyOverrides {
return overrides;
}
export function setOverrides(
newOverrides: ReactNativeFeatureFlagsJsOnlyOverrides,
): void {
if (accessedFeatureFlags.size > 0) {
const accessedFeatureFlagsStr = Array.from(accessedFeatureFlags).join(', ');
throw new Error(
`Feature flags were accessed before being overridden: ${accessedFeatureFlagsStr}`,
);
}
Object.assign(overrides, newOverrides);
}

Просмотреть файл

@ -1,78 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
describe('ReactNativeFeatureFlags', () => {
beforeEach(() => {
jest.resetModules();
});
it('should provide default values for common flags if the native module is NOT available', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
expect(ReactNativeFeatureFlags.commonTestFlag()).toBe(false);
});
it('should access and cache common flags from the native module if it is available', () => {
const commonTestFlagFn = jest.fn(() => true);
jest.doMock('../NativeReactNativeFeatureFlags', () => ({
__esModule: true,
default: {
commonTestFlag: commonTestFlagFn,
},
}));
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
expect(commonTestFlagFn).toHaveBeenCalledTimes(0);
expect(ReactNativeFeatureFlags.commonTestFlag()).toBe(true);
expect(commonTestFlagFn).toHaveBeenCalledTimes(1);
expect(ReactNativeFeatureFlags.commonTestFlag()).toBe(true);
expect(commonTestFlagFn).toHaveBeenCalledTimes(1);
});
it('should provide default values for JS-only flags', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
expect(ReactNativeFeatureFlags.jsOnlyTestFlag()).toBe(false);
});
it('should access and cache overridden JS-only flags', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
const jsOnlyTestFlagFn = jest.fn(() => true);
ReactNativeFeatureFlags.override({
jsOnlyTestFlag: jsOnlyTestFlagFn,
});
expect(jsOnlyTestFlagFn).toHaveBeenCalledTimes(0);
expect(ReactNativeFeatureFlags.jsOnlyTestFlag()).toBe(true);
expect(jsOnlyTestFlagFn).toHaveBeenCalledTimes(1);
expect(ReactNativeFeatureFlags.jsOnlyTestFlag()).toBe(true);
expect(jsOnlyTestFlagFn).toHaveBeenCalledTimes(1);
});
it('should throw an error if any of the flags has been accessed before overridding', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
ReactNativeFeatureFlags.commonTestFlag();
expect(() =>
ReactNativeFeatureFlags.override({
jsOnlyTestFlag: () => true,
}),
).toThrow(
'Feature flags were accessed before being overridden: commonTestFlag',
);
});
});

Просмотреть файл

@ -33,13 +33,6 @@ function describe(message) {
try {
echo('Executing JavaScript tests');
describe('Test: feature flags codegen');
if (exec(`${YARN_BINARY} run featureflags-check`).code) {
echo('Failed to run featureflags check.');
exitCode = 1;
throw Error(exitCode);
}
describe('Test: eslint');
if (exec(`${YARN_BINARY} run lint`).code) {
echo('Failed to run eslint.');