diff --git a/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativePartialAnnotationTurboModule.js b/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativePartialAnnotationTurboModule.js new file mode 100644 index 00000000000000..604224ad9be932 --- /dev/null +++ b/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativePartialAnnotationTurboModule.js @@ -0,0 +1,35 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export type SomeObj = {| + a: string, + b?: boolean, +|}; + +export type PartialSomeObj = $Partial; + +export interface Spec extends TurboModule { + +getSomeObj: () => SomeObj; + +getPartialSomeObj: () => $Partial; + +getSomeObjFromPartialSomeObj: (value: $Partial) => SomeObj; + +getPartialPartial: ( + value1: $Partial, + value2: PartialSomeObj, + ) => SomeObj; +} + +export default (TurboModuleRegistry.getEnforcing( + 'NativePartialAnnotationTurboModule', +): Spec); diff --git a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap index 13d1139ab9c54b..5a2dd6a2343779 100644 --- a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap +++ b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap @@ -430,6 +430,74 @@ namespace facebook { }; } // namespace react } // namespace facebook +namespace JS { + namespace NativePartialAnnotationTurboModule { + struct SpecGetSomeObjFromPartialSomeObjValue { + NSString *a() const; + std::optional b() const; + + SpecGetSomeObjFromPartialSomeObjValue(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:(id)json; +@end +namespace JS { + namespace NativePartialAnnotationTurboModule { + struct SpecGetPartialPartialValue1 { + NSString *a() const; + std::optional b() const; + + SpecGetPartialPartialValue1(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:(id)json; +@end +namespace JS { + namespace NativePartialAnnotationTurboModule { + struct SpecGetPartialPartialValue2 { + NSString *a() const; + std::optional b() const; + + SpecGetPartialPartialValue2(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:(id)json; +@end +@protocol NativePartialAnnotationTurboModuleSpec + +- (NSDictionary *)getSomeObj; +- (NSDictionary *)getPartialSomeObj; +- (NSDictionary *)getSomeObjFromPartialSomeObj:(JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue &)value; +- (NSDictionary *)getPartialPartial:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1 &)value1 + value2:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2 &)value2; + +@end +namespace facebook { + namespace react { + /** + * ObjC++ class for module 'NativePartialAnnotationTurboModule' + */ + class JSI_EXPORT NativePartialAnnotationTurboModuleSpecJSI : public ObjCTurboModule { + public: + NativePartialAnnotationTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; + } // namespace react +} // namespace facebook @protocol NativePromiseTurboModuleSpec @@ -1069,6 +1137,36 @@ inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(const In inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(Constants i) : _factory(^{ return i.unsafeRawValue(); }) {} +inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::a() const +{ + id const p = _v[@\\"a\\"]; + return RCTBridgingToOptionalString(p); +} +inline std::optional JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::b() const +{ + id const p = _v[@\\"b\\"]; + return RCTBridgingToOptionalBool(p); +} +inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::a() const +{ + id const p = _v[@\\"a\\"]; + return RCTBridgingToOptionalString(p); +} +inline std::optional JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::b() const +{ + id const p = _v[@\\"b\\"]; + return RCTBridgingToOptionalBool(p); +} +inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::a() const +{ + id const p = _v[@\\"a\\"]; + return RCTBridgingToOptionalString(p); +} +inline std::optional JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::b() const +{ + id const p = _v[@\\"b\\"]; + return RCTBridgingToOptionalBool(p); +} inline double JS::NativeSampleTurboModule::SpecGetObjectShapeArg::prop() const { @@ -1622,6 +1720,74 @@ namespace facebook { }; } // namespace react } // namespace facebook +namespace JS { + namespace NativePartialAnnotationTurboModule { + struct SpecGetSomeObjFromPartialSomeObjValue { + NSString *a() const; + std::optional b() const; + + SpecGetSomeObjFromPartialSomeObjValue(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:(id)json; +@end +namespace JS { + namespace NativePartialAnnotationTurboModule { + struct SpecGetPartialPartialValue1 { + NSString *a() const; + std::optional b() const; + + SpecGetPartialPartialValue1(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:(id)json; +@end +namespace JS { + namespace NativePartialAnnotationTurboModule { + struct SpecGetPartialPartialValue2 { + NSString *a() const; + std::optional b() const; + + SpecGetPartialPartialValue2(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:(id)json; +@end +@protocol NativePartialAnnotationTurboModuleSpec + +- (NSDictionary *)getSomeObj; +- (NSDictionary *)getPartialSomeObj; +- (NSDictionary *)getSomeObjFromPartialSomeObj:(JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue &)value; +- (NSDictionary *)getPartialPartial:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1 &)value1 + value2:(JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2 &)value2; + +@end +namespace facebook { + namespace react { + /** + * ObjC++ class for module 'NativePartialAnnotationTurboModule' + */ + class JSI_EXPORT NativePartialAnnotationTurboModuleSpecJSI : public ObjCTurboModule { + public: + NativePartialAnnotationTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; + } // namespace react +} // namespace facebook @protocol NativePromiseTurboModuleSpec @@ -2261,6 +2427,36 @@ inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(const In inline JS::NativeOptionalObjectTurboModule::Constants::Builder::Builder(Constants i) : _factory(^{ return i.unsafeRawValue(); }) {} +inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::a() const +{ + id const p = _v[@\\"a\\"]; + return RCTBridgingToOptionalString(p); +} +inline std::optional JS::NativePartialAnnotationTurboModule::SpecGetSomeObjFromPartialSomeObjValue::b() const +{ + id const p = _v[@\\"b\\"]; + return RCTBridgingToOptionalBool(p); +} +inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::a() const +{ + id const p = _v[@\\"a\\"]; + return RCTBridgingToOptionalString(p); +} +inline std::optional JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue1::b() const +{ + id const p = _v[@\\"b\\"]; + return RCTBridgingToOptionalBool(p); +} +inline NSString *JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::a() const +{ + id const p = _v[@\\"a\\"]; + return RCTBridgingToOptionalString(p); +} +inline std::optional JS::NativePartialAnnotationTurboModule::SpecGetPartialPartialValue2::b() const +{ + id const p = _v[@\\"b\\"]; + return RCTBridgingToOptionalBool(p); +} inline double JS::NativeSampleTurboModule::SpecGetObjectShapeArg::prop() const { @@ -2620,6 +2816,61 @@ namespace facebook { } } // namespace react } // namespace facebook +@implementation RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2) ++ (RCTManagedPointer *)JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +namespace facebook { + namespace react { + + static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObj(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getSomeObj\\", @selector(getSomeObj), args, count); + } + + static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialSomeObj(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getPartialSomeObj\\", @selector(getPartialSomeObj), args, count); + } + + static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObjFromPartialSomeObj(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getSomeObjFromPartialSomeObj\\", @selector(getSomeObjFromPartialSomeObj:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialPartial(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getPartialPartial\\", @selector(getPartialPartial:value2:), args, count); + } + + NativePartialAnnotationTurboModuleSpecJSI::NativePartialAnnotationTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_[\\"getSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObj}; + + + methodMap_[\\"getPartialSomeObj\\"] = MethodMetadata {0, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialSomeObj}; + + + methodMap_[\\"getSomeObjFromPartialSomeObj\\"] = MethodMetadata {1, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getSomeObjFromPartialSomeObj}; + setMethodArgConversionSelector(@\\"getSomeObjFromPartialSomeObj\\", 0, @\\"JS_NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue:\\"); + + methodMap_[\\"getPartialPartial\\"] = MethodMetadata {2, __hostFunction_NativePartialAnnotationTurboModuleSpecJSI_getPartialPartial}; + setMethodArgConversionSelector(@\\"getPartialPartial\\", 0, @\\"JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue1:\\"); + setMethodArgConversionSelector(@\\"getPartialPartial\\", 1, @\\"JS_NativePartialAnnotationTurboModule_SpecGetPartialPartialValue2:\\"); + } + } // namespace react +} // namespace facebook namespace facebook { namespace react { diff --git a/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js b/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js index b4017e8dd14e78..53a03bafec54d3 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/parsers-primitives-test.js @@ -21,6 +21,7 @@ const { emitNumber, emitInt32, emitObject, + emitPartial, emitPromise, emitRootTag, emitVoid, @@ -454,30 +455,94 @@ describe('emitObject', () => { expect(result).toEqual(expected); }); }); +}); - describe('emitFloat', () => { - describe('when nullable is true', () => { - it('returns nullable type annotation', () => { - const result = emitFloat(true); - const expected = { - type: 'NullableTypeAnnotation', +describe('emitPartial', () => { + describe('when nullable is true', () => { + it('returns nullable type annotation', () => { + const props = [ + { + name: 'a', + optional: true, typeAnnotation: { - type: 'FloatTypeAnnotation', + type: 'StringTypeAnnotation', }, - }; + }, + { + name: 'b', + optional: true, + typeAnnotation: { + type: 'BooleanTypeAnnotation', + }, + }, + ]; - expect(result).toEqual(expected); - }); + const result = emitPartial(true, props); + + const expected = { + type: 'NullableTypeAnnotation', + typeAnnotation: { + type: 'ObjectTypeAnnotation', + properties: props, + }, + }; + + expect(result).toEqual(expected); }); - describe('when nullable is false', () => { - it('returns non nullable type annotation', () => { - const result = emitFloat(false); - const expected = { + }); + describe('when nullable is false', () => { + it('returns non nullable type annotation', () => { + const props = [ + { + name: 'a', + optional: true, + typeAnnotation: { + type: 'StringTypeAnnotation', + }, + }, + { + name: 'b', + optional: true, + typeAnnotation: { + type: 'BooleanTypeAnnotation', + }, + }, + ]; + + const result = emitPartial(false, props); + + const expected = { + type: 'ObjectTypeAnnotation', + properties: props, + }; + + expect(result).toEqual(expected); + }); + }); +}); + +describe('emitFloat', () => { + describe('when nullable is true', () => { + it('returns nullable type annotation', () => { + const result = emitFloat(true); + const expected = { + type: 'NullableTypeAnnotation', + typeAnnotation: { type: 'FloatTypeAnnotation', - }; + }, + }; - expect(result).toEqual(expected); - }); + expect(result).toEqual(expected); + }); + }); + describe('when nullable is false', () => { + it('returns non nullable type annotation', () => { + const result = emitFloat(false); + const expected = { + type: 'FloatTypeAnnotation', + }; + + expect(result).toEqual(expected); }); }); }); diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js index df2687fc9a7a83..58a33721bc1d59 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js @@ -288,6 +288,68 @@ export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); `; +const NATIVE_MODULE_WITH_PARTIALS = ` +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../RCTExport'; +import * as TurboModuleRegistry from '../TurboModuleRegistry'; + +export type SomeObj = {| + a: string, + b?: boolean, +|}; + +export interface Spec extends TurboModule { + +getSomeObj: () => SomeObj; + +getPartialSomeObj: () => $Partial; + +getSomeObjFromPartialSomeObj: (value: $Partial) => SomeObj; +} + +export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); + +`; + +const NATIVE_MODULE_WITH_PARTIALS_COMPLEX = ` +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../RCTExport'; +import * as TurboModuleRegistry from '../TurboModuleRegistry'; + +export type SomeObj = {| + a: string, + b?: boolean, +|}; + +export type PartialSomeObj = $Partial; + +export interface Spec extends TurboModule { + +getPartialPartial: (value1: $Partial, value2: PartialSomeObj) => SomeObj +} + +export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); + +`; + const NATIVE_MODULE_WITH_ROOT_TAG = ` /** * Copyright (c) Meta Platforms, Inc. and affiliates. @@ -732,6 +794,8 @@ module.exports = { NATIVE_MODULE_WITH_COMPLEX_OBJECTS_WITH_NULLABLE_KEY, NATIVE_MODULE_WITH_SIMPLE_OBJECT, NATIVE_MODULE_WITH_UNSAFE_OBJECT, + NATIVE_MODULE_WITH_PARTIALS, + NATIVE_MODULE_WITH_PARTIALS_COMPLEX, NATIVE_MODULE_WITH_ROOT_TAG, NATIVE_MODULE_WITH_NULLABLE_PARAM, NATIVE_MODULE_WITH_BASIC_ARRAY, diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap index 7e1eb7fd2b6a20..390e3be33c30fd 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap @@ -1431,6 +1431,212 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W }" `; +exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliases': { + 'SomeObj': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + 'spec': { + 'properties': [ + { + 'name': 'getSomeObj', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'SomeObj' + }, + 'params': [] + } + }, + { + 'name': 'getPartialSomeObj', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + }, + 'params': [] + } + }, + { + 'name': 'getSomeObjFromPartialSomeObj', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'SomeObj' + }, + 'params': [ + { + 'name': 'value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + +exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS_COMPLEX 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliases': { + 'SomeObj': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + 'spec': { + 'properties': [ + { + 'name': 'getPartialPartial', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'SomeObj' + }, + 'params': [ + { + 'name': 'value1', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'value2', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE 1`] = ` "{ 'modules': { 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 f89169c240be52..eff16b613d8a07 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -42,6 +42,7 @@ const { emitNumber, emitInt32, emitObject, + emitPartial, emitPromise, emitRootTag, emitVoid, @@ -155,6 +156,40 @@ function translateTypeAnnotation( case 'Object': { return emitObject(nullable); } + case '$Partial': { + if (typeAnnotation.typeParameters.params.length !== 1) { + throw new Error( + 'Partials only support annotating exactly one parameter.', + ); + } + + const annotatedElement = + types[typeAnnotation.typeParameters.params[0].id.name]; + + if (!annotatedElement) { + throw new Error( + 'Partials only support annotating a type parameter.', + ); + } + + const properties = annotatedElement.right.properties.map(prop => { + return { + name: prop.key.name, + optional: true, + typeAnnotation: translateTypeAnnotation( + hasteModuleName, + prop.value, + types, + aliasMap, + tryParse, + cxxOnly, + parser, + ), + }; + }); + + return emitPartial(nullable, properties); + } default: { return translateDefault( hasteModuleName, diff --git a/packages/react-native-codegen/src/parsers/parsers-primitives.js b/packages/react-native-codegen/src/parsers/parsers-primitives.js index 60ee07bc9de83e..e9af9b41bbbd46 100644 --- a/packages/react-native-codegen/src/parsers/parsers-primitives.js +++ b/packages/react-native-codegen/src/parsers/parsers-primitives.js @@ -30,6 +30,7 @@ import type { ReservedTypeAnnotation, StringTypeAnnotation, VoidTypeAnnotation, + NativeModuleObjectTypeAnnotation, } from '../CodegenSchema'; import type {Parser} from './parser'; import type { @@ -243,6 +244,16 @@ function emitObject( }); } +function emitPartial( + nullable: boolean, + properties: Array<$FlowFixMe>, +): Nullable { + return wrapNullable(nullable, { + type: 'ObjectTypeAnnotation', + properties, + }); +} + function emitFloat( nullable: boolean, ): Nullable { @@ -370,6 +381,7 @@ module.exports = { emitInt32, emitNumber, emitObject, + emitPartial, emitPromise, emitRootTag, emitVoid, 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 56b22b61841504..ead2dde77b13d8 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 @@ -302,6 +302,60 @@ export interface Spec extends TurboModule { export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); `; +const NATIVE_MODULE_WITH_PARTIALS = ` +/** + * 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 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export type SomeObj = { + a: string, + b?: boolean, +}; + +export interface Spec extends TurboModule { + getSomeObj: () => SomeObj; + getPartialSomeObj: () => Partial; + getSomeObjFromPartialSomeObj: (value: Partial) => SomeObj; +} + +export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); +`; + +const NATIVE_MODULE_WITH_PARTIALS_COMPLEX = ` +/** + * 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 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export type SomeObj = { + a: string, + b?: boolean, +}; + +export type PartialSomeObj = Partial; + +export interface Spec extends TurboModule { + getPartialPartial: (value1: Partial, value2: PartialSomeObj) => SomeObj; +} + +export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); +`; + const NATIVE_MODULE_WITH_ROOT_TAG = ` /** * Copyright (c) Meta Platforms, Inc. and affiliates. @@ -754,6 +808,8 @@ module.exports = { NATIVE_MODULE_WITH_COMPLEX_OBJECTS_WITH_NULLABLE_KEY, NATIVE_MODULE_WITH_SIMPLE_OBJECT, NATIVE_MODULE_WITH_UNSAFE_OBJECT, + NATIVE_MODULE_WITH_PARTIALS, + NATIVE_MODULE_WITH_PARTIALS_COMPLEX, NATIVE_MODULE_WITH_ROOT_TAG, NATIVE_MODULE_WITH_NULLABLE_PARAM, NATIVE_MODULE_WITH_BASIC_ARRAY, 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 d5ed3ec8c416a0..d6f4f9d4e3679e 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 @@ -1737,6 +1737,212 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_OB }" `; +exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliases': { + 'SomeObj': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + 'spec': { + 'properties': [ + { + 'name': 'getSomeObj', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'SomeObj' + }, + 'params': [] + } + }, + { + 'name': 'getPartialSomeObj', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + }, + 'params': [] + } + }, + { + 'name': 'getSomeObjFromPartialSomeObj', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'SomeObj' + }, + 'params': [ + { + 'name': 'value', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + +exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PARTIALS_COMPLEX 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliases': { + 'SomeObj': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': false, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + 'spec': { + 'properties': [ + { + 'name': 'getPartialPartial', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'TypeAliasTypeAnnotation', + 'name': 'SomeObj' + }, + 'params': [ + { + 'name': 'value1', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'value2', + 'optional': false, + 'typeAnnotation': { + 'type': 'ObjectTypeAnnotation', + 'properties': [ + { + 'name': 'a', + 'optional': true, + 'typeAnnotation': { + 'type': 'StringTypeAnnotation' + } + }, + { + 'name': 'b', + 'optional': true, + 'typeAnnotation': { + 'type': 'BooleanTypeAnnotation' + } + } + ] + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_PROMISE 1`] = ` "{ 'modules': { 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 b1df8711a58b92..6097b5b11824c8 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -42,6 +42,7 @@ const { emitNumber, emitInt32, emitObject, + emitPartial, emitPromise, emitRootTag, emitVoid, @@ -172,6 +173,42 @@ function translateTypeAnnotation( case 'Object': { return emitObject(nullable); } + case 'Partial': { + if (typeAnnotation.typeParameters.params.length !== 1) { + throw new Error( + 'Partials only support annotating exactly one parameter.', + ); + } + + const annotatedElement = + types[typeAnnotation.typeParameters.params[0].typeName.name]; + + if (!annotatedElement) { + throw new Error( + 'Partials only support annotating a type parameter.', + ); + } + + const properties = annotatedElement.typeAnnotation.members.map( + member => { + return { + name: member.key.name, + optional: true, + typeAnnotation: translateTypeAnnotation( + hasteModuleName, + member.typeAnnotation.typeAnnotation, + types, + aliasMap, + tryParse, + cxxOnly, + parser, + ), + }; + }, + ); + + return emitPartial(nullable, properties); + } default: { return translateDefault( hasteModuleName,