From e4ef685dd75f09f22b0122e83fc94bc9d2df8a97 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 16 May 2025 05:59:05 -0700 Subject: [PATCH] Restore legacy semantics of modulesConformingToProtocol (#51381) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/51381 Changelog: [General][Fixed] Fixed codegen breaking when a subset of `modulesConformingToProtocol` fields was specified or when the value was string D70822061 introduced a new way of defininf modules and components in codegen, but accidentally introduced two breaking changes to the legacy syntax: - before that diff, in case of 1:1 mapping, the value of the fileds could be a string, while after, it required it to be an array - before that diff, not all of the fields on `modulesConformingToProtocol` had to be defined in `package.json`, while after, it required all fields to be defined even if unused Reviewed By: cipolleschi Differential Revision: D74875251 fbshipit-source-id: 610103b508f1462b4de01725f9b0a87341571197 --- .../__fixtures__/test-app-legacy/package.json | 37 ++ .../generate-artifacts-executor-test.js.snap | 499 +++++++++++++++++- .../generate-artifacts-executor-test.js | 180 +++---- .../generateCustomURLHandlers.js | 14 +- 4 files changed, 626 insertions(+), 104 deletions(-) create mode 100644 packages/react-native/scripts/codegen/__fixtures__/test-app-legacy/package.json diff --git a/packages/react-native/scripts/codegen/__fixtures__/test-app-legacy/package.json b/packages/react-native/scripts/codegen/__fixtures__/test-app-legacy/package.json new file mode 100644 index 00000000000..3e9e3fc51b7 --- /dev/null +++ b/packages/react-native/scripts/codegen/__fixtures__/test-app-legacy/package.json @@ -0,0 +1,37 @@ +{ + "name": "test-app-legacy", + "version": "0.0.0", + "private": true, + "scripts": { + }, + "dependencies": { + }, + "devDependencies": { + }, + "codegenConfig": { + "name": "TestAppConfig", + "type": "all", + "android": { + "javaPackageName": "com.testApp" + }, + "ios": { + "modulesConformingToProtocol": { + "RCTImageURLLoader": "RCTTestAppDeprecatedImageURLLoader", + "RCTURLRequestHandler": "RCTTestAppDeprecatedURLRequestHandler" + }, + "modulesProvider": { + "TestAppDeprecatedImageURLLoader": "RCTTestAppDeprecatedImageURLLoader", + "TestAppDeprecatedURLRequestHandler": "RCTTestAppDeprecatedURLRequestHandler", + "TestAppDeprecatedImageDataDecoder": "RCTTestAppDeprecatedImageDataDecoder" + }, + "componentProvider": { + "TestAppDeprecatedComponent": "RCTTestAppDeprecatedComponentClass" + }, + "unstableModulesRequiringMainQueueSetup": [ + "RCTTestAppDeprecatedImageURLLoader", + "RCTTestAppDeprecatedURLRequestHandler", + "RCTTestAppDeprecatedImageDataDecoder" + ] + } + } +} diff --git a/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap b/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap index 38256dd89bc..489a99be272 100644 --- a/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap +++ b/packages/react-native/scripts/codegen/__tests__/__snapshots__/generate-artifacts-executor-test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`execute "RCTAppDependencyProvider.h" should match snapshot 1`] = ` +exports[`execute test-app "RCTAppDependencyProvider.h" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_END " `; -exports[`execute "RCTAppDependencyProvider.mm" should match snapshot 1`] = ` +exports[`execute test-app "RCTAppDependencyProvider.mm" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -73,7 +73,7 @@ exports[`execute "RCTAppDependencyProvider.mm" should match snapshot 1`] = ` " `; -exports[`execute "RCTModuleProviders.h" should match snapshot 1`] = ` +exports[`execute test-app "RCTModuleProviders.h" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -93,7 +93,7 @@ exports[`execute "RCTModuleProviders.h" should match snapshot 1`] = ` " `; -exports[`execute "RCTModuleProviders.mm" should match snapshot 1`] = ` +exports[`execute test-app "RCTModuleProviders.mm" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -159,7 +159,7 @@ exports[`execute "RCTModuleProviders.mm" should match snapshot 1`] = ` " `; -exports[`execute "RCTModulesConformingToProtocolsProvider.h" should match snapshot 1`] = ` +exports[`execute test-app "RCTModulesConformingToProtocolsProvider.h" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -181,7 +181,7 @@ exports[`execute "RCTModulesConformingToProtocolsProvider.h" should match snapsh " `; -exports[`execute "RCTModulesConformingToProtocolsProvider.mm" should match snapshot 1`] = ` +exports[`execute test-app "RCTModulesConformingToProtocolsProvider.mm" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -248,7 +248,7 @@ exports[`execute "RCTModulesConformingToProtocolsProvider.mm" should match snaps " `; -exports[`execute "RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = ` +exports[`execute test-app "RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -268,7 +268,7 @@ exports[`execute "RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = " `; -exports[`execute "RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] = ` +exports[`execute test-app "RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -305,7 +305,7 @@ exports[`execute "RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] " `; -exports[`execute "RCTUnstableModulesRequiringMainQueueSetupProvider.h" should match snapshot 1`] = ` +exports[`execute test-app "RCTUnstableModulesRequiringMainQueueSetupProvider.h" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -323,7 +323,7 @@ exports[`execute "RCTUnstableModulesRequiringMainQueueSetupProvider.h" should ma " `; -exports[`execute "RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should match snapshot 1`] = ` +exports[`execute test-app "RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should match snapshot 1`] = ` "/* * Copyright (c) Meta Platforms, Inc. and affiliates. * @@ -357,7 +357,7 @@ exports[`execute "RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should m " `; -exports[`execute "ReactAppDependencyProvider.podspec" should match snapshot 1`] = ` +exports[`execute test-app "ReactAppDependencyProvider.podspec" should match snapshot 1`] = ` "# Copyright (c) Meta Platforms, Inc. and affiliates. # # This source code is licensed under the MIT license found in the @@ -395,7 +395,482 @@ end " `; -exports[`execute "ReactCodegen.podspec" should match snapshot 1`] = ` +exports[`execute test-app "ReactCodegen.podspec" should match snapshot 1`] = ` +"# 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. + +version = \\"1000.0.0\\" +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 we’re 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 + +use_frameworks = ENV['USE_FRAMEWORKS'] != nil +folly_compiler_flags = Helpers::Constants.folly_config[:compiler_flags] +boost_compiler_flags = Helpers::Constants.boost_config[:compiler_flags] + +header_search_paths = [ + \\"\\\\\\"$(PODS_ROOT)/ReactNativeDependencies\\\\\\"\\", + \\"\\\\\\"\${PODS_ROOT}/Headers/Public/ReactCodegen/react/renderer/components\\\\\\"\\", + \\"\\\\\\"$(PODS_ROOT)/Headers/Private/React-Fabric\\\\\\"\\", + \\"\\\\\\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\\\\\\"\\", + \\"\\\\\\"$(PODS_ROOT)/Headers/Private/Yoga\\\\\\"\\", + \\"\\\\\\"$(PODS_TARGET_SRCROOT)\\\\\\"\\", +] +framework_search_paths = [] + +if use_frameworks + ReactNativePodsUtils.create_header_search_path_for_frameworks(\\"PODS_CONFIGURATION_BUILD_DIR\\", \\"React-Fabric\\", \\"React_Fabric\\", [\\"react/renderer/components/view/platform/cxx\\"]) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks(\\"PODS_CONFIGURATION_BUILD_DIR\\", \\"React-FabricImage\\", \\"React_FabricImage\\", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks(\\"PODS_CONFIGURATION_BUILD_DIR\\", \\"React-graphics\\", \\"React_graphics\\", [\\"react/renderer/graphics/platform/ios\\"])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks(\\"PODS_CONFIGURATION_BUILD_DIR\\", \\"ReactCommon\\", \\"ReactCommon\\", [\\"react/nativemodule/core\\"])) + .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-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}\\\\\\"\\" + } +end + +Pod::Spec.new do |s| + s.name = \\"ReactCodegen\\" + s.version = version + s.summary = 'Temp pod for generated files for React Native' + s.homepage = 'https://facebook.com/' + s.license = 'Unlicense' + s.authors = 'Facebook' + s.compiler_flags = \\"#{folly_compiler_flags} #{boost_compiler_flags} -Wno-nullability-completeness -std=c++20\\" + s.source = { :git => '' } + s.header_mappings_dir = './' + s.platforms = min_supported_versions + s.source_files = \\"**/*.{h,mm,cpp}\\" + s.exclude_files = \\"RCTAppDependencyProvider.{h,mm}\\" # these files are generated in the same codegen path but needs to belong to a different pod + s.pod_target_xcconfig = { + \\"HEADER_SEARCH_PATHS\\" => header_search_paths.join(' '), + \\"FRAMEWORK_SEARCH_PATHS\\" => framework_search_paths, + \\"OTHER_CPLUSPLUSFLAGS\\" => \\"$(inherited) #{folly_compiler_flags} #{boost_compiler_flags}\\" + } + + s.dependency \\"React-jsiexecutor\\" + s.dependency \\"RCTRequired\\" + s.dependency \\"RCTTypeSafety\\" + s.dependency \\"React-Core\\" + s.dependency \\"React-jsi\\" + s.dependency \\"ReactCommon/turbomodule/bridging\\" + s.dependency \\"ReactCommon/turbomodule/core\\" + s.dependency \\"React-NativeModulesApple\\" + s.dependency 'React-graphics' + s.dependency 'React-rendererdebug' + s.dependency 'React-Fabric' + s.dependency 'React-FabricImage' + s.dependency 'React-debug' + s.dependency 'React-utils' + s.dependency 'React-featureflags' + s.dependency 'React-RCTAppDelegate' + + depend_on_js_engine(s) + add_rn_third_party_dependencies(s) + + s.script_phases = { + 'name' => 'Generate Specs', + 'execution_position' => :before_compile, + 'input_files' => [], + 'show_env_vars_in_log' => true, + 'output_files' => [\\"\${DERIVED_FILE_DIR}/react-codegen.log\\"], + 'script': <<-SCRIPT +pushd \\"$PODS_ROOT/../\\" > /dev/null +RCT_SCRIPT_POD_INSTALLATION_ROOT=$(pwd) +popd >/dev/null + +export RCT_SCRIPT_RN_DIR=\\"$RCT_SCRIPT_POD_INSTALLATION_ROOT/../../../../..\\" +export RCT_SCRIPT_APP_PATH=\\"$RCT_SCRIPT_POD_INSTALLATION_ROOT/..\\" +export RCT_SCRIPT_OUTPUT_DIR=\\"$RCT_SCRIPT_POD_INSTALLATION_ROOT\\" +export RCT_SCRIPT_TYPE=\\"withCodegenDiscovery\\" + +SCRIPT_PHASES_SCRIPT=\\"$RCT_SCRIPT_RN_DIR/scripts/react_native_pods_utils/script_phases.sh\\" +WITH_ENVIRONMENT=\\"$RCT_SCRIPT_RN_DIR/scripts/xcode/with-environment.sh\\" +/bin/sh -c \\"$WITH_ENVIRONMENT $SCRIPT_PHASES_SCRIPT\\" +SCRIPT + } + +end +" +`; + +exports[`execute test-app-legacy "RCTAppDependencyProvider.h" should match snapshot 1`] = ` +"/* + * 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. + */ + + +#import + +#if __has_include() +#import +#elif __has_include() +#import +#else +#import \\"RCTDependencyProvider.h\\" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTAppDependencyProvider : NSObject + +@end + +NS_ASSUME_NONNULL_END +" +`; + +exports[`execute test-app-legacy "RCTAppDependencyProvider.mm" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import \\"RCTAppDependencyProvider.h\\" +#import +#import +#import +#import + +@implementation RCTAppDependencyProvider + +- (nonnull NSArray *)URLRequestHandlerClassNames { + return RCTModulesConformingToProtocolsProvider.URLRequestHandlerClassNames; +} + +- (nonnull NSArray *)imageDataDecoderClassNames { + return RCTModulesConformingToProtocolsProvider.imageDataDecoderClassNames; +} + +- (nonnull NSArray *)imageURLLoaderClassNames { + return RCTModulesConformingToProtocolsProvider.imageURLLoaderClassNames; +} + +- (nonnull NSArray *)unstableModulesRequiringMainQueueSetup { + return RCTUnstableModulesRequiringMainQueueSetupProvider.modules; +} + +- (nonnull NSDictionary> *)thirdPartyFabricComponents { + return RCTThirdPartyComponentsProvider.thirdPartyFabricComponents; +} + +- (nonnull NSDictionary> *)moduleProviders { + return RCTModuleProviders.moduleProviders; +} + +@end +" +`; + +exports[`execute test-app-legacy "RCTModuleProviders.h" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import + +@protocol RCTModuleProvider; + +@interface RCTModuleProviders: NSObject + ++ (NSDictionary> *)moduleProviders; + +@end +" +`; + +exports[`execute test-app-legacy "RCTModuleProviders.mm" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import + +#import \\"RCTModuleProviders.h\\" +#import +#import + +@implementation RCTModuleProviders + ++ (NSDictionary> *)moduleProviders +{ + static NSDictionary> *providers = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + NSDictionary * moduleMapping = @{ + @\\"TestAppDeprecatedImageURLLoader\\": @\\"RCTTestAppDeprecatedImageURLLoader\\", // test-app-legacy + @\\"TestAppDeprecatedURLRequestHandler\\": @\\"RCTTestAppDeprecatedURLRequestHandler\\", // test-app-legacy + @\\"TestAppDeprecatedImageDataDecoder\\": @\\"RCTTestAppDeprecatedImageDataDecoder\\", // test-app-legacy + }; + + NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:moduleMapping.count]; + + for (NSString *key in moduleMapping) { + NSString * moduleProviderName = moduleMapping[key]; + Class klass = NSClassFromString(moduleProviderName); + if (!klass) { + RCTLogError(@\\"Module provider %@ cannot be found in the runtime\\", moduleProviderName); + continue; + } + + id instance = [klass new]; + if (![instance respondsToSelector:@selector(getTurboModule:)]) { + RCTLogError(@\\"Module provider %@ does not conform to RCTModuleProvider\\", moduleProviderName); + continue; + } + + [dict setObject:instance forKey:key]; + } + + providers = dict; + }); + + return providers; +} + +@end +" +`; + +exports[`execute test-app-legacy "RCTModulesConformingToProtocolsProvider.h" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import + +@interface RCTModulesConformingToProtocolsProvider: NSObject + ++(NSArray *)imageURLLoaderClassNames; + ++(NSArray *)imageDataDecoderClassNames; + ++(NSArray *)URLRequestHandlerClassNames; + +@end +" +`; + +exports[`execute test-app-legacy "RCTModulesConformingToProtocolsProvider.mm" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import \\"RCTModulesConformingToProtocolsProvider.h\\" + +@implementation RCTModulesConformingToProtocolsProvider + ++(NSArray *)imageURLLoaderClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + @\\"RCTTestAppDeprecatedImageURLLoader\\" + ]; + }); + + return classNames; +} + ++(NSArray *)imageDataDecoderClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + + ]; + }); + + return classNames; +} + ++(NSArray *)URLRequestHandlerClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + @\\"RCTTestAppDeprecatedURLRequestHandler\\" + ]; + }); + + return classNames; +} + +@end +" +`; + +exports[`execute test-app-legacy "RCTThirdPartyComponentsProvider.h" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import + +@protocol RCTComponentViewProtocol; + +@interface RCTThirdPartyComponentsProvider: NSObject + ++ (NSDictionary> *)thirdPartyFabricComponents; + +@end +" +`; + +exports[`execute test-app-legacy "RCTThirdPartyComponentsProvider.mm" should match snapshot 1`] = ` +"/* + * 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. + */ + + +#import + +#import \\"RCTThirdPartyComponentsProvider.h\\" +#import + +@implementation RCTThirdPartyComponentsProvider + ++ (NSDictionary> *)thirdPartyFabricComponents +{ + static NSDictionary> *thirdPartyComponents = nil; + static dispatch_once_t nativeComponentsToken; + + dispatch_once(&nativeComponentsToken, ^{ + thirdPartyComponents = @{ + + }; + }); + + return thirdPartyComponents; +} + +@end +" +`; + +exports[`execute test-app-legacy "RCTUnstableModulesRequiringMainQueueSetupProvider.h" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import + +@interface RCTUnstableModulesRequiringMainQueueSetupProvider: NSObject + ++(NSArray *)modules; + +@end +" +`; + +exports[`execute test-app-legacy "RCTUnstableModulesRequiringMainQueueSetupProvider.mm" should match snapshot 1`] = ` +"/* + * 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. + */ + +#import \\"RCTUnstableModulesRequiringMainQueueSetupProvider.h\\" + +@implementation RCTUnstableModulesRequiringMainQueueSetupProvider + ++(NSArray *)modules +{ + return @[ + @\\"RCTTestAppDeprecatedImageURLLoader\\", + @\\"RCTTestAppDeprecatedURLRequestHandler\\", + @\\"RCTTestAppDeprecatedImageDataDecoder\\" + ]; +} + +@end +" +`; + +exports[`execute test-app-legacy "ReactAppDependencyProvider.podspec" should match snapshot 1`] = ` +"# 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. + +version = \\"1000.0.0\\" +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 we’re 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 + +Pod::Spec.new do |s| + s.name = \\"ReactAppDependencyProvider\\" + s.version = version + s.summary = \\"The third party dependency provider for the app\\" + s.homepage = \\"https://reactnative.dev/\\" + s.documentation_url = \\"https://reactnative.dev/\\" + s.license = \\"MIT\\" + s.author = \\"Meta Platforms, Inc. and its affiliates\\" + s.platforms = min_supported_versions + s.source = source + s.source_files = \\"**/RCTAppDependencyProvider.{h,mm}\\" + + # This guard prevent to install the dependencies when we run \`pod install\` in the old architecture. + s.pod_target_xcconfig = { + \\"CLANG_CXX_LANGUAGE_STANDARD\\" => rct_cxx_language_standard(), + \\"DEFINES_MODULE\\" => \\"YES\\" + } + + s.dependency \\"ReactCodegen\\" +end +" +`; + +exports[`execute test-app-legacy "ReactCodegen.podspec" should match snapshot 1`] = ` "# Copyright (c) Meta Platforms, Inc. and affiliates. # # This source code is licensed under the MIT license found in the diff --git a/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js b/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js index 44aafd91f7c..67f597d5247 100644 --- a/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js +++ b/packages/react-native/scripts/codegen/__tests__/generate-artifacts-executor-test.js @@ -28,105 +28,107 @@ const packageJson = JSON.stringify({ name: 'react-native', }); -describe('execute', () => { - const appDir = path.join(__dirname, '../__fixtures__/test-app'); - const outputDir = path.join(appDir, 'temp'); +['test-app', 'test-app-legacy'].forEach(appName => { + describe(`execute ${appName}`, () => { + const appDir = path.join(__dirname, '../__fixtures__', appName); + const outputDir = path.join(appDir, 'temp'); - beforeAll(() => { - execute(appDir, 'ios', outputDir, 'app', false); - }); - - afterAll(() => { - fs.rmdirSync(outputDir, {recursive: true}); - }); - - [ - 'RCTAppDependencyProvider.h', - 'RCTAppDependencyProvider.mm', - 'RCTModuleProviders.h', - 'RCTModuleProviders.mm', - 'RCTModulesConformingToProtocolsProvider.h', - 'RCTModulesConformingToProtocolsProvider.mm', - 'RCTThirdPartyComponentsProvider.h', - 'RCTThirdPartyComponentsProvider.mm', - 'ReactAppDependencyProvider.podspec', - 'ReactCodegen.podspec', - 'RCTUnstableModulesRequiringMainQueueSetupProvider.h', - 'RCTUnstableModulesRequiringMainQueueSetupProvider.mm', - ].forEach(file => { - it(`"${file}" should match snapshot`, () => { - const generatedFileDir = path.join(outputDir, 'build/generated/ios'); - const generatedFile = path.join(generatedFileDir, file); - expect(fs.existsSync(generatedFile)).toBe(true); - expect(fs.readFileSync(generatedFile, 'utf8')).toMatchSnapshot(); + beforeAll(() => { + execute(appDir, 'ios', outputDir, 'app', false); }); - }); -}); -describe('extractLibrariesFromJSON', () => { - it('extracts a single dependency when config has no libraries', () => { - let configFile = fixtures.noLibrariesConfigFile; - let libraries = extractLibrariesFromJSON(configFile, '.'); - expect(libraries.length).toBe(1); - expect(libraries[0]).toEqual({ - config: { - name: 'AppModules', - type: 'all', - jsSrcsDir: '.', - }, - libraryPath: '.', + afterAll(() => { + fs.rmdirSync(outputDir, {recursive: true}); + }); + + [ + 'RCTAppDependencyProvider.h', + 'RCTAppDependencyProvider.mm', + 'RCTModuleProviders.h', + 'RCTModuleProviders.mm', + 'RCTModulesConformingToProtocolsProvider.h', + 'RCTModulesConformingToProtocolsProvider.mm', + 'RCTThirdPartyComponentsProvider.h', + 'RCTThirdPartyComponentsProvider.mm', + 'ReactAppDependencyProvider.podspec', + 'ReactCodegen.podspec', + 'RCTUnstableModulesRequiringMainQueueSetupProvider.h', + 'RCTUnstableModulesRequiringMainQueueSetupProvider.mm', + ].forEach(file => { + it(`"${file}" should match snapshot`, () => { + const generatedFileDir = path.join(outputDir, 'build/generated/ios'); + const generatedFile = path.join(generatedFileDir, file); + expect(fs.existsSync(generatedFile)).toBe(true); + expect(fs.readFileSync(generatedFile, 'utf8')).toMatchSnapshot(); + }); }); }); - it("doesn't extract libraries when they are present but empty", () => { - const configFile = {codegenConfig: {libraries: []}}; - let libraries = extractLibrariesFromJSON(configFile, rootPath); - expect(libraries.length).toBe(0); - }); + describe('extractLibrariesFromJSON', () => { + it('extracts a single dependency when config has no libraries', () => { + let configFile = fixtures.noLibrariesConfigFile; + let libraries = extractLibrariesFromJSON(configFile, '.'); + expect(libraries.length).toBe(1); + expect(libraries[0]).toEqual({ + config: { + name: 'AppModules', + type: 'all', + jsSrcsDir: '.', + }, + libraryPath: '.', + }); + }); - it('extracts libraries when they are present and not empty', () => { - const configFile = fixtures.singleLibraryCodegenConfig; - let libraries = extractLibrariesFromJSON(configFile, rootPath); - expect(libraries.length).toBe(1); - expect(libraries[0]).toEqual({ - config: { - name: 'react-native', - type: 'all', - jsSrcsDir: '.', - }, - libraryPath: rootPath, + it("doesn't extract libraries when they are present but empty", () => { + const configFile = {codegenConfig: {libraries: []}}; + let libraries = extractLibrariesFromJSON(configFile, rootPath); + expect(libraries.length).toBe(0); }); - }); - it('extract codegenConfig with multiple dependencies', () => { - const configFile = fixtures.multipleLibrariesCodegenConfig; - const myDependency = 'my-dependency'; - const myDependencyPath = path.join(__dirname, myDependency); - let libraries = extractLibrariesFromJSON(configFile, myDependencyPath); - expect(libraries.length).toBe(3); - expect(libraries[0]).toEqual({ - config: { - name: 'react-native', - type: 'all', - jsSrcsDir: '.', - }, - libraryPath: myDependencyPath, + it('extracts libraries when they are present and not empty', () => { + const configFile = fixtures.singleLibraryCodegenConfig; + let libraries = extractLibrariesFromJSON(configFile, rootPath); + expect(libraries.length).toBe(1); + expect(libraries[0]).toEqual({ + config: { + name: 'react-native', + type: 'all', + jsSrcsDir: '.', + }, + libraryPath: rootPath, + }); }); - expect(libraries[1]).toEqual({ - config: { - name: 'my-component', - type: 'components', - jsSrcsDir: 'component/js', - }, - libraryPath: myDependencyPath, - }); - expect(libraries[2]).toEqual({ - config: { - name: 'my-module', - type: 'module', - jsSrcsDir: 'module/js', - }, - libraryPath: myDependencyPath, + + it('extract codegenConfig with multiple dependencies', () => { + const configFile = fixtures.multipleLibrariesCodegenConfig; + const myDependency = 'my-dependency'; + const myDependencyPath = path.join(__dirname, myDependency); + let libraries = extractLibrariesFromJSON(configFile, myDependencyPath); + expect(libraries.length).toBe(3); + expect(libraries[0]).toEqual({ + config: { + name: 'react-native', + type: 'all', + jsSrcsDir: '.', + }, + libraryPath: myDependencyPath, + }); + expect(libraries[1]).toEqual({ + config: { + name: 'my-component', + type: 'components', + jsSrcsDir: 'component/js', + }, + libraryPath: myDependencyPath, + }); + expect(libraries[2]).toEqual({ + config: { + name: 'my-module', + type: 'module', + jsSrcsDir: 'module/js', + }, + libraryPath: myDependencyPath, + }); }); }); }); diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js b/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js index 42404840248..ed5c2696fb7 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js @@ -30,6 +30,8 @@ function generateCustomURLHandlers(libraries, outputDir) { const imageDataDecoderModules = new Set(); const urlRequestHandlersModules = new Set(); + const wrapInArrayIfNecessary = value => + Array.isArray(value) || value == null ? value : [value]; // Old API for (const library of libraries) { const modulesConformingToProtocol = @@ -38,13 +40,19 @@ function generateCustomURLHandlers(libraries, outputDir) { continue; } - modulesConformingToProtocol.RCTImageURLLoader.forEach(moduleName => { + wrapInArrayIfNecessary( + modulesConformingToProtocol.RCTImageURLLoader, + )?.forEach(moduleName => { imageURLLoaderModules.add(moduleName); }); - modulesConformingToProtocol.RCTImageDataDecoder.forEach(moduleName => { + wrapInArrayIfNecessary( + modulesConformingToProtocol.RCTImageDataDecoder, + )?.forEach(moduleName => { imageDataDecoderModules.add(moduleName); }); - modulesConformingToProtocol.RCTURLRequestHandler.forEach(moduleName => { + wrapInArrayIfNecessary( + modulesConformingToProtocol.RCTURLRequestHandler, + )?.forEach(moduleName => { urlRequestHandlersModules.add(moduleName); }); }