diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js index defe5722f29..629976a74c4 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js @@ -22,6 +22,20 @@ const {StructCollector} = require('./StructCollector'); type FilesOutput = Map; +const SwiftCompatibleDeclarationTemplate = ({ + hasteModuleName, + protocolMethods, +}: $ReadOnly<{ + hasteModuleName: string, + protocolMethods: string, +}>) => ` +@protocol ${hasteModuleName}Spec + +${protocolMethods} + +@end +` + const ModuleDeclarationTemplate = ({ hasteModuleName, structDeclarations, @@ -58,6 +72,51 @@ namespace facebook::react { }; } // namespace facebook::react`; +const SwiftCompatibleHeaderFileTemplate = ({ + headerFileName, + moduleDeclarations, + assumeNonnull, +}: $ReadOnly<{ + headerFileName: string, + moduleDeclarations: string, + assumeNonnull: boolean, +}>) => { + const headerFileNameWithNoExt = headerFileName + .replace(/\.h$/, '') + .replace(/-/, ''); + + return ( + `/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * ${'@'}generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +// Avoid multiple includes of ${headerFileNameWithNoExt} symbols +#ifndef ${headerFileNameWithNoExt}_H +#define ${headerFileNameWithNoExt}_H + +#import +#import +#import + +` + + (assumeNonnull ? '\nNS_ASSUME_NONNULL_BEGIN\n' : '') + + moduleDeclarations + + '\n' + + (assumeNonnull ? '\nNS_ASSUME_NONNULL_END\n' : '\n') + + `#endif // ${headerFileNameWithNoExt}_H` + + '\n' + ); +}; + const HeaderFileTemplate = ({ headerFileName, moduleDeclarations, @@ -150,6 +209,7 @@ module.exports = { const nativeModules = getModules(schema); const moduleDeclarations: Array = []; + const swiftCompatibleModulesDeclarations: Array = []; const structInlineMethods: Array = []; const moduleImplementations: Array = []; @@ -209,6 +269,15 @@ module.exports = { }), ); + swiftCompatibleModulesDeclarations.push( + SwiftCompatibleDeclarationTemplate({ + hasteModuleName: hasteModuleName, + protocolMethods: methodSerializations + .map(({protocolMethod}) => protocolMethod) + .join('\n'), + }), + ); + structInlineMethods.push(methodStrs.join('\n')); moduleImplementations.push( @@ -232,6 +301,13 @@ module.exports = { assumeNonnull, }); + const swiftCompatibleHeaderFileName = `${libraryName}-Swift.h`; + const swiftHeaderFile = SwiftCompatibleHeaderFileTemplate({ + headerFileName: swiftCompatibleHeaderFileName, + moduleDeclarations: swiftCompatibleModulesDeclarations.join('\n'), + assumeNonnull, + }); + const sourceFileName = `${libraryName}-generated.mm`; const sourceFile = SourceFileTemplate({ headerFileName, @@ -240,6 +316,7 @@ module.exports = { return new Map([ [headerFileName, headerFile], + [swiftCompatibleHeaderFileName, swiftHeaderFile], [sourceFileName, sourceFile], ]); },