@@ -26,8 +26,11 @@ import type {ParserType} from '../errors';
2626const { Visitor} = require ( '../flow/Visitor' ) ;
2727const { wrapComponentSchema} = require ( '../schema.js' ) ;
2828const { buildComponentSchema} = require ( '../flow/components' ) ;
29- const { buildModuleSchema} = require ( '../flow/modules' ) ;
30- const { isModuleRegistryCall} = require ( '../utils.js' ) ;
29+ const { buildModuleSchema} = require ( '../parsers-commons.js' ) ;
30+ const {
31+ isModuleRegistryCall,
32+ createParserErrorCapturer,
33+ } = require ( '../utils.js' ) ;
3134const {
3235 ParserError,
3336 UnsupportedObjectPropertyTypeAnnotationParserError,
@@ -36,6 +39,9 @@ const {
3639 IncorrectModuleRegistryCallArityParserError,
3740 IncorrectModuleRegistryCallArgumentTypeParserError,
3841 UntypedModuleRegistryCallParserError,
42+ ModuleInterfaceNotFoundParserError,
43+ MoreThanOneModuleInterfaceParserError,
44+ MisnamedModuleInterfaceParserError,
3945} = require ( '../errors' ) ;
4046
4147import { MockedParser } from '../parserMock' ;
@@ -45,8 +51,9 @@ const parser = new MockedParser();
4551
4652const flowParser = new FlowParser ( ) ;
4753
48- const flowTranslateTypeAnnotation = require ( '../flow/modules/index' ) ;
54+ const { flowTranslateTypeAnnotation} = require ( '../flow/modules/index' ) ;
4955const typeScriptTranslateTypeAnnotation = require ( '../typescript/modules/index' ) ;
56+ const { resolveTypeAnnotation} = require ( '../flow/utils' ) ;
5057
5158beforeEach ( ( ) => {
5259 jest . clearAllMocks ( ) ;
@@ -396,7 +403,9 @@ describe('buildSchemaFromConfigType', () => {
396403 const buildComponentSchemaMock = jest . fn (
397404 ( _ast , _parser ) => componentSchemaMock ,
398405 ) ;
399- const buildModuleSchemaMock = jest . fn ( ( _0 , _1 , _2 , _3 ) => moduleSchemaMock ) ;
406+ const buildModuleSchemaMock = jest . fn (
407+ ( _0 , _1 , _2 , _3 , _4 , _5 ) => moduleSchemaMock ,
408+ ) ;
400409
401410 const buildSchemaFromConfigTypeHelper = (
402411 configType : 'module' | 'component' | 'none' ,
@@ -410,6 +419,8 @@ describe('buildSchemaFromConfigType', () => {
410419 buildComponentSchemaMock ,
411420 buildModuleSchemaMock ,
412421 parser ,
422+ resolveTypeAnnotation ,
423+ flowTranslateTypeAnnotation ,
413424 ) ;
414425
415426 describe ( 'when configType is none' , ( ) => {
@@ -491,6 +502,8 @@ describe('buildSchemaFromConfigType', () => {
491502 astMock ,
492503 expect . any ( Function ) ,
493504 parser ,
505+ resolveTypeAnnotation ,
506+ flowTranslateTypeAnnotation ,
494507 ) ;
495508
496509 expect ( buildComponentSchemaMock ) . not . toHaveBeenCalled ( ) ;
@@ -661,6 +674,8 @@ describe('buildSchema', () => {
661674 buildModuleSchema ,
662675 Visitor ,
663676 parser ,
677+ resolveTypeAnnotation ,
678+ flowTranslateTypeAnnotation ,
664679 ) ;
665680
666681 expect ( getConfigTypeSpy ) . not . toHaveBeenCalled ( ) ;
@@ -693,6 +708,8 @@ describe('buildSchema', () => {
693708 buildModuleSchema ,
694709 Visitor ,
695710 flowParser ,
711+ resolveTypeAnnotation ,
712+ flowTranslateTypeAnnotation ,
696713 ) ;
697714
698715 expect ( getConfigTypeSpy ) . toHaveBeenCalledTimes ( 1 ) ;
@@ -746,6 +763,8 @@ describe('buildSchema', () => {
746763 buildModuleSchema ,
747764 Visitor ,
748765 flowParser ,
766+ resolveTypeAnnotation ,
767+ flowTranslateTypeAnnotation ,
749768 ) ;
750769
751770 expect ( getConfigTypeSpy ) . toHaveBeenCalledTimes ( 1 ) ;
@@ -1007,3 +1026,208 @@ describe('parseModuleName', () => {
10071026 } ) ;
10081027 } ) ;
10091028} ) ;
1029+
1030+ describe ( 'buildModuleSchema' , ( ) => {
1031+ const hasteModuleName = 'TestModuleName' ;
1032+ const [ , tryParse ] = createParserErrorCapturer ( ) ;
1033+ const language = flowParser . language ( ) ;
1034+ const NATIVE_MODULE = `
1035+ import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
1036+ import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
1037+
1038+ export interface Spec extends TurboModule {
1039+ +getArray: (a: Array<any>) => Array<string>;
1040+ }
1041+
1042+ export default (TurboModuleRegistry.getEnforcing<Spec>(
1043+ 'SampleTurboModule',
1044+ ): Spec);
1045+ ` ;
1046+
1047+ describe ( 'throwIfModuleInterfaceNotFound' , ( ) => {
1048+ it ( 'should throw ModuleInterfaceNotFoundParserError if no module interface is found' , ( ) => {
1049+ const ast = flowParser . getAst ( '' ) ;
1050+ const expected = new ModuleInterfaceNotFoundParserError (
1051+ hasteModuleName ,
1052+ ast ,
1053+ language ,
1054+ ) ;
1055+
1056+ expect ( ( ) =>
1057+ buildModuleSchema (
1058+ hasteModuleName ,
1059+ ast ,
1060+ tryParse ,
1061+ flowParser ,
1062+ resolveTypeAnnotation ,
1063+ flowTranslateTypeAnnotation ,
1064+ ) ,
1065+ ) . toThrow ( expected ) ;
1066+ } ) ;
1067+
1068+ it ( 'should not throw ModuleInterfaceNotFoundParserError if module interface is found' , ( ) => {
1069+ const ast = flowParser . getAst ( NATIVE_MODULE ) ;
1070+
1071+ expect ( ( ) =>
1072+ buildModuleSchema (
1073+ hasteModuleName ,
1074+ ast ,
1075+ tryParse ,
1076+ flowParser ,
1077+ resolveTypeAnnotation ,
1078+ flowTranslateTypeAnnotation ,
1079+ ) ,
1080+ ) . not . toThrow ( ) ;
1081+ } ) ;
1082+ } ) ;
1083+
1084+ describe ( 'throwIfMoreThanOneModuleInterfaceParser' , ( ) => {
1085+ it ( 'should throw an error if mulitple module interfaces are found' , ( ) => {
1086+ const contents = `
1087+ import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
1088+ import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
1089+
1090+ export interface Spec extends TurboModule {
1091+ +getBool: (arg: boolean) => boolean; }
1092+ export interface SpecOther extends TurboModule {
1093+ +getArray: (a: Array<any>) => Array<string>;
1094+ }
1095+ ` ;
1096+ const ast = flowParser . getAst ( contents ) ;
1097+ const types = flowParser . getTypes ( ast ) ;
1098+ const moduleSpecs = Object . values ( types ) . filter ( t =>
1099+ flowParser . isModuleInterface ( t ) ,
1100+ ) ;
1101+ const expected = new MoreThanOneModuleInterfaceParserError (
1102+ hasteModuleName ,
1103+ moduleSpecs ,
1104+ moduleSpecs . map ( node => node . id . name ) ,
1105+ language ,
1106+ ) ;
1107+
1108+ expect ( ( ) =>
1109+ buildModuleSchema (
1110+ hasteModuleName ,
1111+ ast ,
1112+ tryParse ,
1113+ flowParser ,
1114+ resolveTypeAnnotation ,
1115+ flowTranslateTypeAnnotation ,
1116+ ) ,
1117+ ) . toThrow ( expected ) ;
1118+ } ) ;
1119+
1120+ it ( 'should not throw an error if exactly one module interface is found' , ( ) => {
1121+ const ast = flowParser . getAst ( NATIVE_MODULE ) ;
1122+
1123+ expect ( ( ) =>
1124+ buildModuleSchema (
1125+ hasteModuleName ,
1126+ ast ,
1127+ tryParse ,
1128+ flowParser ,
1129+ resolveTypeAnnotation ,
1130+ flowTranslateTypeAnnotation ,
1131+ ) ,
1132+ ) . not . toThrow ( ) ;
1133+ } ) ;
1134+ } ) ;
1135+
1136+ describe ( 'throwIfModuleInterfaceIsMisnamed' , ( ) => {
1137+ it ( 'should throw an error if module interface is misnamed' , ( ) => {
1138+ const contents = `
1139+ import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
1140+ import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
1141+
1142+ export interface MisnamedSpec extends TurboModule {
1143+ +getArray: (a: Array<any>) => Array<string>;
1144+ }
1145+
1146+ export default (TurboModuleRegistry.getEnforcing<Spec>(
1147+ 'SampleTurboModule',
1148+ ): Spec);
1149+ ` ;
1150+ const ast = flowParser . getAst ( contents ) ;
1151+ const types = flowParser . getTypes ( ast ) ;
1152+ const moduleSpecs = Object . values ( types ) . filter ( t =>
1153+ flowParser . isModuleInterface ( t ) ,
1154+ ) ;
1155+ const [ moduleSpec ] = moduleSpecs ;
1156+
1157+ const expected = new MisnamedModuleInterfaceParserError (
1158+ hasteModuleName ,
1159+ moduleSpec . id ,
1160+ language ,
1161+ ) ;
1162+
1163+ expect ( ( ) =>
1164+ buildModuleSchema (
1165+ hasteModuleName ,
1166+ ast ,
1167+ tryParse ,
1168+ flowParser ,
1169+ resolveTypeAnnotation ,
1170+ flowTranslateTypeAnnotation ,
1171+ ) ,
1172+ ) . toThrow ( expected ) ;
1173+ } ) ;
1174+
1175+ it ( 'should not throw an error if module interface is correctly named' , ( ) => {
1176+ const ast = flowParser . getAst ( NATIVE_MODULE ) ;
1177+
1178+ expect ( ( ) =>
1179+ buildModuleSchema (
1180+ hasteModuleName ,
1181+ ast ,
1182+ tryParse ,
1183+ flowParser ,
1184+ resolveTypeAnnotation ,
1185+ flowTranslateTypeAnnotation ,
1186+ ) ,
1187+ ) . not . toThrow ( ) ;
1188+ } ) ;
1189+ } ) ;
1190+
1191+ it ( 'should return valid module schema' , ( ) => {
1192+ const ast = flowParser . getAst ( NATIVE_MODULE ) ;
1193+ const schmeaMock = {
1194+ aliasMap : { } ,
1195+ enumMap : { } ,
1196+ excludedPlatforms : undefined ,
1197+ moduleName : 'SampleTurboModule' ,
1198+ spec : {
1199+ properties : [
1200+ {
1201+ name : 'getArray' ,
1202+ optional : false ,
1203+ typeAnnotation : {
1204+ params : [
1205+ {
1206+ name : 'a' ,
1207+ optional : false ,
1208+ typeAnnotation : { type : 'ArrayTypeAnnotation' } ,
1209+ } ,
1210+ ] ,
1211+ returnTypeAnnotation : {
1212+ elementType : { type : 'StringTypeAnnotation' } ,
1213+ type : 'ArrayTypeAnnotation' ,
1214+ } ,
1215+ type : 'FunctionTypeAnnotation' ,
1216+ } ,
1217+ } ,
1218+ ] ,
1219+ } ,
1220+ type : 'NativeModule' ,
1221+ } ;
1222+ const schema = buildModuleSchema (
1223+ hasteModuleName ,
1224+ ast ,
1225+ tryParse ,
1226+ flowParser ,
1227+ resolveTypeAnnotation ,
1228+ flowTranslateTypeAnnotation ,
1229+ ) ;
1230+
1231+ expect ( schema ) . toEqual ( schmeaMock ) ;
1232+ } ) ;
1233+ } ) ;
0 commit comments