diff --git a/packages/react-native-codegen/src/parsers/__tests__/utils-test.js b/packages/react-native-codegen/src/parsers/__tests__/utils-test.js index ace9c57787d6d1..3da5f6a8f06ca0 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/utils-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/utils-test.js @@ -14,6 +14,7 @@ const { extractNativeModuleName, createParserErrorCapturer, + verifyPlatforms, visit, } = require('../utils.js'); const {ParserError} = require('../errors'); @@ -117,6 +118,71 @@ describe('createParserErrorCapturer', () => { }); }); +describe('verifyPlatforms', () => { + it('exclude android given an iOS only module', () => { + let result = verifyPlatforms('NativeSampleTurboModule', [ + 'SampleTurboModuleIOS', + ]); + + expect(result.cxxOnly).toBe(false); + expect(result.excludedPlatforms).toEqual(['android']); + + result = verifyPlatforms('NativeSampleTurboModuleIOS', [ + 'SampleTurboModule', + ]); + expect(result.cxxOnly).toBe(false); + expect(result.excludedPlatforms).toEqual(['android']); + + result = verifyPlatforms('NativeSampleTurboModuleIOS', [ + 'SampleTurboModuleIOS', + ]); + expect(result.cxxOnly).toBe(false); + expect(result.excludedPlatforms).toEqual(['android']); + }); + + it('exclude iOS given an android only module', () => { + let result = verifyPlatforms('NativeSampleTurboModule', [ + 'SampleTurboModuleAndroid', + ]); + + expect(result.cxxOnly).toBe(false); + expect(result.excludedPlatforms).toEqual(['iOS']); + + result = verifyPlatforms('NativeSampleTurboModuleAndroid', [ + 'SampleTurboModule', + ]); + expect(result.cxxOnly).toBe(false); + expect(result.excludedPlatforms).toEqual(['iOS']); + + result = verifyPlatforms('NativeSampleTurboModuleAndroid', [ + 'SampleTurboModuleAndroid', + ]); + expect(result.cxxOnly).toBe(false); + expect(result.excludedPlatforms).toEqual(['iOS']); + }); + + it('exclude iOS and android given a Cxx only module', () => { + let result = verifyPlatforms('NativeSampleTurboModule', [ + 'SampleTurboModuleCxx', + ]); + + expect(result.cxxOnly).toBe(true); + expect(result.excludedPlatforms).toEqual(['iOS', 'android']); + + result = verifyPlatforms('NativeSampleTurboModuleCxx', [ + 'SampleTurboModule', + ]); + expect(result.cxxOnly).toBe(true); + expect(result.excludedPlatforms).toEqual(['iOS', 'android']); + + result = verifyPlatforms('NativeSampleTurboModuleCxx', [ + 'SampleTurboModuleCxx', + ]); + expect(result.cxxOnly).toBe(true); + expect(result.excludedPlatforms).toEqual(['iOS', 'android']); + }); +}); + describe('visit', () => { describe('when the astNode is null', () => { it("doesn't call the visitor function", () => { diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index 813a90ceb4c0cb..d9e6b13abe01d6 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -66,6 +66,7 @@ const { UnsupportedObjectPropertyValueTypeAnnotationParserError, IncorrectModuleRegistryCallArgumentTypeParserError, } = require('../../errors.js'); +const {verifyPlatforms} = require('../../utils'); const { throwIfModuleInterfaceNotFound, @@ -691,19 +692,10 @@ function buildModuleSchema( // Eventually this should be made explicit in the Flow type itself. // Also check the hasteModuleName for platform suffix. // Note: this shape is consistent with ComponentSchema. - let cxxOnly = false; - const excludedPlatforms = []; - const namesToValidate = [...moduleNames, hasteModuleName]; - namesToValidate.forEach(name => { - if (name.endsWith('Android')) { - excludedPlatforms.push('iOS'); - } else if (name.endsWith('IOS')) { - excludedPlatforms.push('android'); - } else if (name.endsWith('Cxx')) { - cxxOnly = true; - excludedPlatforms.push('iOS', 'android'); - } - }); + const {cxxOnly, excludedPlatforms} = verifyPlatforms( + hasteModuleName, + moduleNames, + ); // $FlowFixMe[missing-type-arg] return (moduleSpec.body.properties: $ReadOnlyArray<$FlowFixMe>) diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index 438d7462955b11..90b04f3c38de81 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -66,6 +66,7 @@ const { UnsupportedObjectPropertyValueTypeAnnotationParserError, IncorrectModuleRegistryCallArgumentTypeParserError, } = require('../../errors.js'); +const {verifyPlatforms} = require('../../utils'); const { throwIfUntypedModule, @@ -705,19 +706,10 @@ function buildModuleSchema( // Eventually this should be made explicit in the Flow type itself. // Also check the hasteModuleName for platform suffix. // Note: this shape is consistent with ComponentSchema. - let cxxOnly = false; - const excludedPlatforms = []; - const namesToValidate = [...moduleNames, hasteModuleName]; - namesToValidate.forEach(name => { - if (name.endsWith('Android')) { - excludedPlatforms.push('iOS'); - } else if (name.endsWith('IOS')) { - excludedPlatforms.push('android'); - } else if (name.endsWith('Cxx')) { - cxxOnly = true; - excludedPlatforms.push('iOS', 'android'); - } - }); + const {cxxOnly, excludedPlatforms} = verifyPlatforms( + hasteModuleName, + moduleNames, + ); // $FlowFixMe[missing-type-arg] return (moduleSpec.body.body: $ReadOnlyArray<$FlowFixMe>) diff --git a/packages/react-native-codegen/src/parsers/utils.js b/packages/react-native-codegen/src/parsers/utils.js index 671836f0b49ebb..151c30fb91b1bf 100644 --- a/packages/react-native-codegen/src/parsers/utils.js +++ b/packages/react-native-codegen/src/parsers/utils.js @@ -54,6 +54,42 @@ function createParserErrorCapturer(): [ return [errors, guard]; } +function verifyPlatforms( + hasteModuleName: string, + moduleNames: string[], +): $ReadOnly<{ + cxxOnly: boolean, + excludedPlatforms: Array<'iOS' | 'android'>, +}> { + let cxxOnly = false; + const excludedPlatforms = new Set<'iOS' | 'android'>(); + const namesToValidate = [...moduleNames, hasteModuleName]; + + namesToValidate.forEach(name => { + if (name.endsWith('Android')) { + excludedPlatforms.add('iOS'); + return; + } + + if (name.endsWith('IOS')) { + excludedPlatforms.add('android'); + return; + } + + if (name.endsWith('Cxx')) { + cxxOnly = true; + excludedPlatforms.add('iOS'); + excludedPlatforms.add('android'); + return; + } + }); + + return { + cxxOnly, + excludedPlatforms: Array.from(excludedPlatforms), + }; +} + // TODO(T108222691): Use flow-types for @babel/parser function visit( astNode: $FlowFixMe, @@ -86,5 +122,6 @@ function visit( module.exports = { extractNativeModuleName, createParserErrorCapturer, + verifyPlatforms, visit, };