diff --git a/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js b/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js index a36c9272985..3994fa89938 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/parsers-test.js @@ -110,6 +110,61 @@ describe('FlowParser', () => { expect(parser.callExpressionTypeParameters(node)).toBe(null); }); }); + + describe('computePartialProperties', () => { + it('returns partial properties', () => { + const properties = [ + { + type: 'ObjectTypeProperty', + key: { + type: 'Identifier', + name: 'a', + }, + value: { + type: 'StringTypeAnnotation', + range: [], + }, + }, + { + type: 'ObjectTypeProperty', + key: { + type: 'Identifier', + name: 'b', + }, + optional: true, + value: { + type: 'BooleanTypeAnnotation', + range: [], + }, + }, + ]; + + const expected = [ + { + name: 'a', + optional: true, + typeAnnotation: {type: 'StringTypeAnnotation'}, + }, + { + name: 'b', + optional: true, + typeAnnotation: {type: 'BooleanTypeAnnotation'}, + }, + ]; + + expect( + parser.computePartialProperties( + properties, + 'hasteModuleName', + {}, + {}, + {}, + () => null, + false, + ), + ).toEqual(expected); + }); + }); }); describe('TypeScriptParser', () => { @@ -202,4 +257,73 @@ describe('TypeScriptParser', () => { expect(parser.callExpressionTypeParameters(node)).toBe(null); }); }); + + describe('computePartialProperties', () => { + it('returns partial properties', () => { + const properties = [ + { + type: 'TSPropertySignature', + key: { + type: 'Identifier', + name: 'a', + }, + typeAnnotation: { + type: 'TSTypeAnnotation', + typeAnnotation: { + type: 'TSTypeLiteral', + key: { + type: 'Identifier', + name: 'a', + }, + members: [], + }, + }, + }, + { + type: 'TSPropertySignature', + key: { + type: 'Identifier', + name: 'b', + }, + optional: true, + typeAnnotation: { + type: 'TSTypeAnnotation', + typeAnnotation: { + type: 'TSStringKeyword', + key: { + type: 'Identifier', + name: 'b', + }, + members: [], + }, + }, + }, + ]; + + const expected = [ + { + name: 'a', + optional: true, + typeAnnotation: {properties: [], type: 'ObjectTypeAnnotation'}, + }, + { + name: 'b', + optional: true, + typeAnnotation: {type: 'StringTypeAnnotation'}, + }, + ]; + + expect( + parser.computePartialProperties( + properties, + 'hasteModuleName', + {}, + {}, + {}, + () => null, + false, + ), + ).toEqual(expected); + }); + }); }); 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 4598cc98352..b6870c3674c 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -172,22 +172,15 @@ function translateTypeAnnotation( parser, ); - const properties = annotatedElement.right.properties.map(prop => { - return { - name: prop.key.name, - optional: true, - typeAnnotation: translateTypeAnnotation( - hasteModuleName, - prop.value, - types, - aliasMap, - enumMap, - tryParse, - cxxOnly, - parser, - ), - }; - }); + const properties = parser.computePartialProperties( + annotatedElement.right.properties, + hasteModuleName, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + ); return emitObject(nullable, properties); } diff --git a/packages/react-native-codegen/src/parsers/flow/parser.js b/packages/react-native-codegen/src/parsers/flow/parser.js index a7f7932f801..d57d60e6a9a 100644 --- a/packages/react-native-codegen/src/parsers/flow/parser.js +++ b/packages/react-native-codegen/src/parsers/flow/parser.js @@ -18,10 +18,14 @@ import type { NativeModuleParamTypeAnnotation, NativeModuleEnumMemberType, NativeModuleEnumMembers, + NativeModuleAliasMap, + NativeModuleEnumMap, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type {Parser} from '../parser'; -import type {TypeDeclarationMap} from '../utils'; +import type {ParserErrorCapturer, TypeDeclarationMap} from '../utils'; + +const {flowTranslateTypeAnnotation} = require('./modules'); // $FlowFixMe[untyped-import] there's no flowtype flow-parser const flowParser = require('flow-parser'); @@ -257,6 +261,33 @@ class FlowParser implements Parser { callExpressionTypeParameters(callExpression: $FlowFixMe): $FlowFixMe | null { return callExpression.typeArguments || null; } + + computePartialProperties( + properties: Array<$FlowFixMe>, + hasteModuleName: string, + types: TypeDeclarationMap, + aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, + tryParse: ParserErrorCapturer, + cxxOnly: boolean, + ): Array<$FlowFixMe> { + return properties.map(prop => { + return { + name: prop.key.name, + optional: true, + typeAnnotation: flowTranslateTypeAnnotation( + hasteModuleName, + prop.value, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + this, + ), + }; + }); + } } module.exports = { diff --git a/packages/react-native-codegen/src/parsers/parser.js b/packages/react-native-codegen/src/parsers/parser.js index 1110ac56c50..e4837281acf 100644 --- a/packages/react-native-codegen/src/parsers/parser.js +++ b/packages/react-native-codegen/src/parsers/parser.js @@ -18,9 +18,11 @@ import type { NativeModuleParamTypeAnnotation, NativeModuleEnumMemberType, NativeModuleEnumMembers, + NativeModuleAliasMap, + NativeModuleEnumMap, } from '../CodegenSchema'; import type {ParserType} from './errors'; -import type {TypeDeclarationMap} from './utils'; +import type {ParserErrorCapturer, TypeDeclarationMap} from './utils'; /** * This is the main interface for Parsers of various languages. @@ -161,8 +163,8 @@ export interface Parser { /** * Given a typeAnnotation, it returns the annotated element. - * @paramater typeAnnotation: the annotation for a type. - * @paramater types: a map of type declarations. + * @parameter typeAnnotation: the annotation for a type. + * @parameter types: a map of type declarations. * @returns: the annotated element. */ extractAnnotatedElement( @@ -177,8 +179,29 @@ export interface Parser { /** * Given a callExpression, it returns the typeParameters of the callExpression. - * @paramater callExpression: the callExpression. + * @parameter callExpression: the callExpression. * @returns: the typeParameters of the callExpression or null if it does not exist. */ callExpressionTypeParameters(callExpression: $FlowFixMe): $FlowFixMe | null; + + /** + * Given an array of properties from a Partial type, it returns an array of remaped properties. + * @parameter properties: properties from a Partial types. + * @parameter hasteModuleName: a string with the native module name. + * @parameter types: a map of type declarations. + * @parameter aliasMap: a map of type aliases. + * @parameter enumMap: a map of type enums. + * @parameter tryParse: a parser error capturer. + * @parameter cxxOnly: a boolean specifying if the module is Cxx only. + * @returns: an array of remaped properties + */ + computePartialProperties( + properties: Array<$FlowFixMe>, + hasteModuleName: string, + types: TypeDeclarationMap, + aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, + tryParse: ParserErrorCapturer, + cxxOnly: boolean, + ): Array<$FlowFixMe>; } diff --git a/packages/react-native-codegen/src/parsers/parserMock.js b/packages/react-native-codegen/src/parsers/parserMock.js index dda91725e2a..ca878675dfb 100644 --- a/packages/react-native-codegen/src/parsers/parserMock.js +++ b/packages/react-native-codegen/src/parsers/parserMock.js @@ -20,8 +20,10 @@ import type { NativeModuleParamTypeAnnotation, NativeModuleEnumMemberType, NativeModuleEnumMembers, + NativeModuleAliasMap, + NativeModuleEnumMap, } from '../CodegenSchema'; -import type {TypeDeclarationMap} from './utils'; +import type {ParserErrorCapturer, TypeDeclarationMap} from './utils'; // $FlowFixMe[untyped-import] there's no flowtype flow-parser const flowParser = require('flow-parser'); @@ -184,4 +186,27 @@ export class MockedParser implements Parser { callExpressionTypeParameters(callExpression: $FlowFixMe): $FlowFixMe | null { return callExpression.typeArguments || null; } + + computePartialProperties( + properties: Array<$FlowFixMe>, + hasteModuleName: string, + types: TypeDeclarationMap, + aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, + tryParse: ParserErrorCapturer, + cxxOnly: boolean, + ): Array<$FlowFixMe> { + return [ + { + name: 'a', + optional: true, + typeAnnotation: {type: 'StringTypeAnnotation'}, + }, + { + name: 'b', + optional: true, + typeAnnotation: {type: 'BooleanTypeAnnotation'}, + }, + ]; + } } 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 f316ab1df09..94aa7a3111b 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -253,23 +253,14 @@ function translateTypeAnnotation( parser, ); - const properties = annotatedElement.typeAnnotation.members.map( - member => { - return { - name: member.key.name, - optional: true, - typeAnnotation: translateTypeAnnotation( - hasteModuleName, - member.typeAnnotation.typeAnnotation, - types, - aliasMap, - enumMap, - tryParse, - cxxOnly, - parser, - ), - }; - }, + const properties = parser.computePartialProperties( + annotatedElement.typeAnnotation.members, + hasteModuleName, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, ); return emitObject(nullable, properties); diff --git a/packages/react-native-codegen/src/parsers/typescript/parser.js b/packages/react-native-codegen/src/parsers/typescript/parser.js index 6e09f6a6d88..7e120fcd85f 100644 --- a/packages/react-native-codegen/src/parsers/typescript/parser.js +++ b/packages/react-native-codegen/src/parsers/typescript/parser.js @@ -18,10 +18,14 @@ import type { NativeModuleParamTypeAnnotation, NativeModuleEnumMembers, NativeModuleEnumMemberType, + NativeModuleAliasMap, + NativeModuleEnumMap, } from '../../CodegenSchema'; import type {ParserType} from '../errors'; import type {Parser} from '../parser'; -import type {TypeDeclarationMap} from '../utils'; +import type {ParserErrorCapturer, TypeDeclarationMap} from '../utils'; + +const {typeScriptTranslateTypeAnnotation} = require('./modules'); // $FlowFixMe[untyped-import] Use flow-types for @babel/parser const babelParser = require('@babel/parser'); @@ -243,7 +247,35 @@ class TypeScriptParser implements Parser { callExpressionTypeParameters(callExpression: $FlowFixMe): $FlowFixMe | null { return callExpression.typeParameters || null; } + + computePartialProperties( + properties: Array<$FlowFixMe>, + hasteModuleName: string, + types: TypeDeclarationMap, + aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, + tryParse: ParserErrorCapturer, + cxxOnly: boolean, + ): Array<$FlowFixMe> { + return properties.map(prop => { + return { + name: prop.key.name, + optional: true, + typeAnnotation: typeScriptTranslateTypeAnnotation( + hasteModuleName, + prop.typeAnnotation.typeAnnotation, + types, + aliasMap, + enumMap, + tryParse, + cxxOnly, + this, + ), + }; + }); + } } + module.exports = { TypeScriptParser, };