From 8d58e49f64bd1a1229b9c551a522f4690e701485 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 2 Feb 2023 00:34:37 -0800 Subject: [PATCH 1/8] Add test case for intersection type --- .../__tests__/checkModuleSnaps-test.js | 1 + .../modules/__test_fixtures__/fixtures.js | 45 ++++++++ ...script-module-parser-snapshot-test.js.snap | 107 ++++++++++++++++++ 3 files changed, 153 insertions(+) diff --git a/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js b/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js index e90d3d22d30c0e..1e1fe3909c103f 100644 --- a/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js +++ b/packages/react-native-codegen/src/parsers/consistency/__tests__/checkModuleSnaps-test.js @@ -22,6 +22,7 @@ const tsExtraCases = [ 'NATIVE_MODULE_WITH_ARRAY2_WITH_UNION_AND_TOUPLE', 'NATIVE_MODULE_WITH_BASIC_ARRAY2', 'NATIVE_MODULE_WITH_COMPLEX_ARRAY2', + 'NATIVE_MODULE_WITH_INTERSECTION_TYPES', 'NATIVE_MODULE_WITH_NESTED_INTERFACES', ]; const ignoredCases = []; diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js index ead2dde77b13d8..5f6377869afb1d 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js @@ -239,6 +239,50 @@ export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); `; +const NATIVE_MODULE_WITH_INTERSECTION_TYPES = ` +/** + * 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. + * + * @format + */ + + +import type {TurboModule} from '../RCTExport'; +import * as TurboModuleRegistry from '../TurboModuleRegistry'; + +type Bar = { + z: number +}; + +type Base1 = { + bar1: Bar, +} + +type Base2 = { + bar2: Bar, +} + +type Base3 = Base2 & { + bar3: Bar, +} + +type Foo = Base1 & Base3 & { + bar4: Bar, +}; + +export interface Spec extends TurboModule { + // Exported methods. + foo1: (x: Foo) => Foo; + foo2: (x: Foo) => void; +} + +export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); + +`; + const NATIVE_MODULE_WITH_FLOAT_AND_INT32 = ` /** * Copyright (c) Meta Platforms, Inc. and affiliates. @@ -803,6 +847,7 @@ module.exports = { NATIVE_MODULE_WITH_ALIASES, NATIVE_MODULE_WITH_NESTED_ALIASES, NATIVE_MODULE_WITH_NESTED_INTERFACES, + NATIVE_MODULE_WITH_INTERSECTION_TYPES, NATIVE_MODULE_WITH_PROMISE, NATIVE_MODULE_WITH_COMPLEX_OBJECTS, NATIVE_MODULE_WITH_COMPLEX_OBJECTS_WITH_NULLABLE_KEY, diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap index eed47982636b24..7a64f144fd86f3 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap @@ -1572,6 +1572,113 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_FL }" `; +exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_INTERSECTION_TYPES 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliases': { + 'Bar': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'z', + 'optional': false, + 'typeAnnotation': { + 'type': 'NumberTypeAnnotation' + } + } + ] + }, + 'Foo': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'bar1', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + }, + { + 'name': 'bar2', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + }, + { + 'name': 'bar3', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + }, + { + 'name': 'bar4', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Bar' + } + } + ] + } + }, + 'spec': { + 'properties': [ + { + 'name': 'foo1', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Foo' + }, + 'params': [ + { + 'name': 'x', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Foo' + } + } + ] + } + }, + { + 'name': 'foo2', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'x', + 'optional': false, + 'typeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'Foo' + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_NESTED_ALIASES 1`] = ` "{ 'modules': { From 492a80efbd8c8414e2458f0aa57d296133a76f5e Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 2 Feb 2023 00:47:38 -0800 Subject: [PATCH 2/8] Extract translateObjectTypeAnnotation --- .../src/parsers/typescript/modules/index.js | 139 ++++++++++-------- 1 file changed, 74 insertions(+), 65 deletions(-) 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 18c9ddf13492af..4a058733756e35 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -22,7 +22,11 @@ import type { } from '../../../CodegenSchema'; import type {Parser} from '../../parser'; -import type {ParserErrorCapturer, TypeDeclarationMap} from '../../utils'; +import type { + ParserErrorCapturer, + TypeAliasResolutionStatus, + TypeDeclarationMap, +} from '../../utils'; const {flattenProperties} = require('../components/componentsUtils'); const {visit, isModuleRegistryCall, verifyPlatforms} = require('../../utils'); @@ -74,6 +78,58 @@ const { const language = 'TypeScript'; +function translateObjectTypeAnnotation( + hasteModuleName: string, + /** + * TODO(T108222691): Use flow-types for @babel/parser + */ + nullable: boolean, + objectMembers: $ReadOnlyArray<$FlowFixMe>, + typeResolutionStatus: TypeAliasResolutionStatus, + baseTypes: $ReadOnlyArray, + types: TypeDeclarationMap, + aliasMap: {...NativeModuleAliasMap}, + tryParse: ParserErrorCapturer, + cxxOnly: boolean, + parser: Parser, +): Nullable { + let objectTypeAnnotation = { + type: 'ObjectTypeAnnotation', + // $FlowFixMe[missing-type-arg] + properties: objectMembers + .map>>(property => { + return tryParse(() => { + return parseObjectProperty( + property, + hasteModuleName, + types, + aliasMap, + tryParse, + cxxOnly, + nullable, + translateTypeAnnotation, + parser, + ); + }); + }) + .filter(Boolean), + baseTypes, + }; + + if (objectTypeAnnotation.baseTypes.length === 0) { + // The flow checker does not allow adding a member after an object literal is created + // so here I do it in a reverse way + delete objectTypeAnnotation.baseTypes; + } + + return typeAliasResolution( + typeResolutionStatus, + objectTypeAnnotation, + aliasMap, + nullable, + ); +} + function translateTypeAnnotation( hasteModuleName: string, /** @@ -246,46 +302,19 @@ function translateTypeAnnotation( ); } - let objectTypeAnnotation = { - type: 'ObjectTypeAnnotation', - // $FlowFixMe[missing-type-arg] - properties: (flattenProperties( + return translateObjectTypeAnnotation( + hasteModuleName, + nullable, + (flattenProperties( [typeAnnotation], types, - ): $ReadOnlyArray<$FlowFixMe>) - .map>>( - property => { - return tryParse(() => { - return parseObjectProperty( - property, - hasteModuleName, - types, - aliasMap, - enumMap, - tryParse, - cxxOnly, - nullable, - translateTypeAnnotation, - parser, - ); - }); - }, - ) - .filter(Boolean), - baseTypes, - }; - - if (objectTypeAnnotation.baseTypes.length === 0) { - // The flow checker does not allow adding a member after an object literal is created - // so here I do it in a reverse way - delete objectTypeAnnotation.baseTypes; - } - - return typeAliasResolution( + ): $ReadOnlyArray<$FlowFixMe>), typeResolutionStatus, - objectTypeAnnotation, + [], aliasMap, - nullable, + tryParse, + cxxOnly, + parser, ); } case 'TSTypeLiteral': { @@ -313,36 +342,16 @@ function translateTypeAnnotation( } } - const objectTypeAnnotation = { - type: 'ObjectTypeAnnotation', - // $FlowFixMe[missing-type-arg] - properties: (typeAnnotation.members: Array<$FlowFixMe>) - .map>>( - property => { - return tryParse(() => { - return parseObjectProperty( - property, - hasteModuleName, - types, - aliasMap, - enumMap, - tryParse, - cxxOnly, - nullable, - translateTypeAnnotation, - parser, - ); - }); - }, - ) - .filter(Boolean), - }; - - return typeAliasResolution( + return translateObjectTypeAnnotation( + hasteModuleName, + nullable, + typeAnnotation.members, typeResolutionStatus, - objectTypeAnnotation, + [], aliasMap, - nullable, + tryParse, + cxxOnly, + parser, ); } case 'TSEnumDeclaration': { From 4841ae9d98f4b581557feb24f6141177dcb2cbab Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 2 Feb 2023 00:50:49 -0800 Subject: [PATCH 3/8] ... --- .../src/parsers/typescript/modules/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 4a058733756e35..a0ca381618b663 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -310,7 +310,8 @@ function translateTypeAnnotation( types, ): $ReadOnlyArray<$FlowFixMe>), typeResolutionStatus, - [], + baseTypes, + types, aliasMap, tryParse, cxxOnly, @@ -348,6 +349,7 @@ function translateTypeAnnotation( typeAnnotation.members, typeResolutionStatus, [], + types, aliasMap, tryParse, cxxOnly, From dc9b65cbf2fbccd472cd1c363c3adbbcbc4e29d1 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 2 Feb 2023 00:55:45 -0800 Subject: [PATCH 4/8] Implement TSIntersectionType --- .../src/parsers/typescript/modules/index.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 a0ca381618b663..dfa20afa34a92a 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -27,6 +27,7 @@ import type { TypeAliasResolutionStatus, TypeDeclarationMap, } from '../../utils'; +const {flattenIntersectionType} = require('../parseTopLevelType'); const {flattenProperties} = require('../components/componentsUtils'); const {visit, isModuleRegistryCall, verifyPlatforms} = require('../../utils'); @@ -318,6 +319,23 @@ function translateTypeAnnotation( parser, ); } + case 'TSIntersectionType': { + return translateObjectTypeAnnotation( + hasteModuleName, + nullable, + (flattenProperties( + flattenIntersectionType(typeAnnotation,types), + types, + ): $ReadOnlyArray<$FlowFixMe>), + typeAliasResolutionStatus, + [], + types, + aliasMap, + tryParse, + cxxOnly, + parser, + ); + } case 'TSTypeLiteral': { // if there is TSIndexSignature, then it is a dictionary if (typeAnnotation.members) { From 610e1ca2196f56a01309374d1e9207048a6e8b45 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 2 Feb 2023 00:56:22 -0800 Subject: [PATCH 5/8] yarn prettier --- .../src/parsers/typescript/modules/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 dfa20afa34a92a..0d3de326eb60f1 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -324,7 +324,7 @@ function translateTypeAnnotation( hasteModuleName, nullable, (flattenProperties( - flattenIntersectionType(typeAnnotation,types), + flattenIntersectionType(typeAnnotation, types), types, ): $ReadOnlyArray<$FlowFixMe>), typeAliasResolutionStatus, From 5557480c1608adf44d154bf6ddda89a8d9b54097 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 2 Feb 2023 01:04:48 -0800 Subject: [PATCH 6/8] yarn flow-check-ios --- .../src/parsers/typescript/modules/index.js | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) 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 0d3de326eb60f1..1f977e43fdafa9 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -94,41 +94,47 @@ function translateObjectTypeAnnotation( cxxOnly: boolean, parser: Parser, ): Nullable { - let objectTypeAnnotation = { - type: 'ObjectTypeAnnotation', - // $FlowFixMe[missing-type-arg] - properties: objectMembers - .map>>(property => { - return tryParse(() => { - return parseObjectProperty( - property, - hasteModuleName, - types, - aliasMap, - tryParse, - cxxOnly, - nullable, - translateTypeAnnotation, - parser, - ); - }); - }) - .filter(Boolean), - baseTypes, - }; - - if (objectTypeAnnotation.baseTypes.length === 0) { - // The flow checker does not allow adding a member after an object literal is created - // so here I do it in a reverse way - delete objectTypeAnnotation.baseTypes; - } + // $FlowFixMe[missing-type-arg] + const properties = objectMembers + .map>>(property => { + return tryParse(() => { + return parseObjectProperty( + property, + hasteModuleName, + types, + aliasMap, + tryParse, + cxxOnly, + nullable, + translateTypeAnnotation, + parser, + ); + }); + }) + .filter(Boolean); - return typeAliasResolution( - typeResolutionStatus, - objectTypeAnnotation, - aliasMap, - nullable, - ); + if (baseTypes.length === 0) { + return typeAliasResolution( + typeResolutionStatus, + { + type: 'ObjectTypeAnnotation', + properties, + }, + aliasMap, + nullable, + ); + } else { + return typeAliasResolution( + typeResolutionStatus, + { + type: 'ObjectTypeAnnotation', + properties, + baseTypes, + }, + aliasMap, + nullable, + ); + } } function translateTypeAnnotation( @@ -306,10 +312,7 @@ function translateTypeAnnotation( return translateObjectTypeAnnotation( hasteModuleName, nullable, - (flattenProperties( - [typeAnnotation], - types, - ): $ReadOnlyArray<$FlowFixMe>), + flattenProperties([typeAnnotation], types), typeResolutionStatus, baseTypes, types, @@ -323,11 +326,11 @@ function translateTypeAnnotation( return translateObjectTypeAnnotation( hasteModuleName, nullable, - (flattenProperties( + flattenProperties( flattenIntersectionType(typeAnnotation, types), types, - ): $ReadOnlyArray<$FlowFixMe>), - typeAliasResolutionStatus, + ), + typeResolutionStatus, [], types, aliasMap, From 16c6313e3f954ac0bd360072a418df6579e500d7 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Thu, 2 Feb 2023 17:52:19 -0800 Subject: [PATCH 7/8] Fix comment --- .../src/parsers/typescript/modules/index.js | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) 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 1f977e43fdafa9..fb028dade1a650 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -113,28 +113,26 @@ function translateObjectTypeAnnotation( }) .filter(Boolean); + let objectTypeAnnotation; if (baseTypes.length === 0) { - return typeAliasResolution( - typeResolutionStatus, - { - type: 'ObjectTypeAnnotation', - properties, - }, - aliasMap, - nullable, - ); + objectTypeAnnotation = { + type: 'ObjectTypeAnnotation', + properties, + }; } else { - return typeAliasResolution( - typeResolutionStatus, - { - type: 'ObjectTypeAnnotation', - properties, - baseTypes, - }, - aliasMap, - nullable, - ); + objectTypeAnnotation = { + type: 'ObjectTypeAnnotation', + properties, + baseTypes, + }; } + + return typeAliasResolution( + typeResolutionStatus, + objectTypeAnnotation, + aliasMap, + nullable, + ); } function translateTypeAnnotation( From a2b9ae8d6a282bf6da92231603487a0b32edf064 Mon Sep 17 00:00:00 2001 From: "Zihan Chen (MSFT)" <53799235+ZihanChen-MSFT@users.noreply.github.com> Date: Fri, 3 Feb 2023 14:02:50 -0800 Subject: [PATCH 8/8] Rebase --- .../typescript-module-parser-snapshot-test.js.snap | 3 ++- .../src/parsers/typescript/modules/index.js | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap index 7a64f144fd86f3..6f7033c94407af 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap @@ -1577,7 +1577,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_IN 'modules': { 'NativeSampleTurboModule': { 'type': 'NativeModule', - 'aliases': { + 'aliasMap': { 'Bar': { 'type': 'ObjectTypeAnnotation', 'properties': [ @@ -1628,6 +1628,7 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_IN ] } }, + 'enumMap': {}, 'spec': { 'properties': [ { 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 fb028dade1a650..64cd08459c0858 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -24,7 +24,7 @@ import type { import type {Parser} from '../../parser'; import type { ParserErrorCapturer, - TypeAliasResolutionStatus, + TypeResolutionStatus, TypeDeclarationMap, } from '../../utils'; const {flattenIntersectionType} = require('../parseTopLevelType'); @@ -86,10 +86,11 @@ function translateObjectTypeAnnotation( */ nullable: boolean, objectMembers: $ReadOnlyArray<$FlowFixMe>, - typeResolutionStatus: TypeAliasResolutionStatus, + typeResolutionStatus: TypeResolutionStatus, baseTypes: $ReadOnlyArray, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, + enumMap: {...NativeModuleEnumMap}, tryParse: ParserErrorCapturer, cxxOnly: boolean, parser: Parser, @@ -103,6 +104,7 @@ function translateObjectTypeAnnotation( hasteModuleName, types, aliasMap, + enumMap, tryParse, cxxOnly, nullable, @@ -315,6 +317,7 @@ function translateTypeAnnotation( baseTypes, types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -332,6 +335,7 @@ function translateTypeAnnotation( [], types, aliasMap, + enumMap, tryParse, cxxOnly, parser, @@ -370,6 +374,7 @@ function translateTypeAnnotation( [], types, aliasMap, + enumMap, tryParse, cxxOnly, parser,