Skip to content

Commit e261f02

Browse files
hramosfacebook-github-bot
authored andcommitted
Codegen: List type aliases in modules schema
Summary: The current parser behavior flattens out any object type aliases into ObjectTypeAnnotations. Generators can treat these as regular objects and generate the applicable native code. This, however, can lead to repetition whenever an object type alias is re-used in the same native module. I propose we treat these as a special case, using a TypeAliasTypeAnnotation to denote them as type aliases. Generators can look up the actual signature for a given object alias by referring to the "aliases" array that is provided in the schema. **Proposed schema change:** Adds an "aliases" key to each module in the schema: ``` export type NativeModuleShape = $ReadOnly<{| properties: $ReadOnlyArray<NativeModuleMethodTypeShape>, aliases: $ReadOnlyArray<{| name: string, typeAnnotation: | $ReadOnly<{| type: 'ObjectTypeAnnotation', properties: $ReadOnlyArray<ObjectParamTypeAnnotation>, |}> | $ReadOnly<TypeAliasTypeAnnotation>, |}>, |}>; ``` Example: ``` { modules: { SampleTurboModule: { nativeModules: { SampleTurboModule: { aliases: [], properties: [], }, }, }, }, } ``` Method parameters will now support the new 'TypeAliasTypeAnnotation' wherever a param might have used a 'ObjectTypeAnnotation': ``` export type TypeAliasTypeAnnotation = $ReadOnly<{| type: 'TypeAliasTypeAnnotation', name: string, |}>; ``` Changelog: [Internal] Reviewed By: RSNara Differential Revision: D22200700 fbshipit-source-id: 15684620783c752f2fb482ba4b88d1fd1cc07540
1 parent 0cef464 commit e261f02

14 files changed

Lines changed: 402 additions & 31 deletions

File tree

packages/react-native-codegen/src/CodegenSchema.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ export type StringTypeAnnotation = $ReadOnly<{|
5555
type: 'StringTypeAnnotation',
5656
|}>;
5757

58+
export type TypeAliasTypeAnnotation = $ReadOnly<{|
59+
type: 'TypeAliasTypeAnnotation',
60+
name: string,
61+
|}>;
62+
5863
export type EventObjectPropertyType =
5964
| $ReadOnly<{|
6065
type: 'BooleanTypeAnnotation',
@@ -223,19 +228,25 @@ export type FunctionTypeAnnotationParamTypeAnnotation =
223228
|}>
224229
| $ReadOnly<{|
225230
type: 'ArrayTypeAnnotation',
226-
elementType: ?FunctionTypeAnnotationParamTypeAnnotation,
231+
elementType:
232+
| ?FunctionTypeAnnotationParamTypeAnnotation
233+
| ?TypeAliasTypeAnnotation,
227234
|}>
228235
| $ReadOnly<{|
229236
type: 'ObjectTypeAnnotation',
230237
properties: ?$ReadOnlyArray<ObjectParamTypeAnnotation>,
231238
|}>;
232239

233-
export type FunctionTypeAnnotationReturnArrayElementType = FunctionTypeAnnotationParamTypeAnnotation;
240+
export type FunctionTypeAnnotationReturnArrayElementType =
241+
| FunctionTypeAnnotationParamTypeAnnotation
242+
| TypeAliasTypeAnnotation;
234243

235244
export type ObjectParamTypeAnnotation = $ReadOnly<{|
236245
optional: boolean,
237246
name: string,
238-
typeAnnotation?: FunctionTypeAnnotationParamTypeAnnotation, // TODO (T67898313): Workaround for NativeLinking's use of union type, typeAnnotations should not be optional
247+
typeAnnotation?:
248+
| FunctionTypeAnnotationParamTypeAnnotation
249+
| TypeAliasTypeAnnotation, // TODO (T67898313): Workaround for NativeLinking's use of union type, typeAnnotations should not be optional
239250
|}>;
240251

241252
export type FunctionTypeAnnotationReturn =
@@ -265,7 +276,9 @@ export type FunctionTypeAnnotationReturn =
265276
export type FunctionTypeAnnotationParam = $ReadOnly<{|
266277
nullable: boolean,
267278
name: string,
268-
typeAnnotation: FunctionTypeAnnotationParamTypeAnnotation,
279+
typeAnnotation:
280+
| FunctionTypeAnnotationParamTypeAnnotation
281+
| TypeAliasTypeAnnotation,
269282
|}>;
270283

271284
export type FunctionTypeAnnotation = $ReadOnly<{|
@@ -280,7 +293,13 @@ export type NativeModuleMethodTypeShape = $ReadOnly<{|
280293
typeAnnotation: FunctionTypeAnnotation,
281294
|}>;
282295

296+
export type ObjectTypeAliasTypeShape = $ReadOnly<{|
297+
type: 'ObjectTypeAnnotation',
298+
properties: $ReadOnlyArray<ObjectParamTypeAnnotation>,
299+
|}>;
300+
283301
export type NativeModuleShape = $ReadOnly<{|
302+
aliases: $ReadOnly<{[aliasName: string]: ObjectTypeAliasTypeShape, ...}>,
284303
properties: $ReadOnlyArray<NativeModuleMethodTypeShape>,
285304
|}>;
286305

packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function traverseArg(arg, index): string {
7575
default:
7676
(typeAnnotation.name: empty);
7777
throw new Error(
78-
`Unknown prop type for "${arg.name}, found: ${typeAnnotation.name}"`,
78+
`Unknown prop type for "${arg.name}", found: "${typeAnnotation.name}"`,
7979
);
8080
}
8181
case 'StringTypeAnnotation':
@@ -91,6 +91,7 @@ function traverseArg(arg, index): string {
9191
case 'FunctionTypeAnnotation':
9292
return `std::move(${wrap('.getObject(rt).getFunction(rt)')})`;
9393
case 'GenericObjectTypeAnnotation':
94+
case 'TypeAliasTypeAnnotation': // TODO: Handle aliases
9495
case 'ObjectTypeAnnotation':
9596
return wrap('.getObject(rt)');
9697
case 'AnyTypeAnnotation':
@@ -99,7 +100,7 @@ function traverseArg(arg, index): string {
99100
// TODO (T65847278): Figure out why this does not work.
100101
// (typeAnnotation.type: empty);
101102
throw new Error(
102-
`Unknown prop type for "${arg.name}, found: ${typeAnnotation.type}"`,
103+
`Unknown prop type for "${arg.name}", found: "${typeAnnotation.type}"`,
103104
);
104105
}
105106
}

packages/react-native-codegen/src/generators/modules/GenerateModuleH.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function translatePrimitiveJSTypeToCpp(
7474
return 'int';
7575
case 'BooleanTypeAnnotation':
7676
return 'bool';
77+
// case 'TypeAliasTypeAnnotation': // TODO: Handle aliases
7778
case 'GenericObjectTypeAnnotation':
7879
case 'ObjectTypeAnnotation':
7980
return 'jsi::Object';

packages/react-native-codegen/src/generators/modules/GenerateModuleHObjCpp.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ function translatePrimitiveJSTypeToObjCType(
124124
return nullable ? 'NSNumber *' : 'double';
125125
case 'BooleanTypeAnnotation':
126126
return nullable ? 'NSNumber * _Nullable' : 'BOOL';
127+
case 'TypeAliasTypeAnnotation': // TODO: Handle aliases
127128
case 'GenericObjectTypeAnnotation':
128129
return wrapIntoNullableIfNeeded('NSDictionary *');
129130
case 'ArrayTypeAnnotation':

packages/react-native-codegen/src/generators/modules/ObjCppUtils/GenerateStructs.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ function getElementTypeForArray(
9292
return 'double';
9393
case 'ObjectTypeAnnotation':
9494
return getNamespacedStructName(name, property) + 'Element';
95+
case 'TypeAliasTypeAnnotation': // TODO: Handle aliases
9596
case 'GenericObjectTypeAnnotation':
9697
// TODO(T67565166): Generic objects are not type safe and should be disallowed in the schema. This case should throw an error once it is disallowed in schema.
9798
console.error(
@@ -228,6 +229,7 @@ function getInlineMethodImplementation(
228229
return `RCTBridgingToBool(${element})`;
229230
case 'ObjectTypeAnnotation':
230231
return `${getNamespacedStructName(name, property)}Element(${element})`;
232+
case 'TypeAliasTypeAnnotation': // TODO: Handle aliases
231233
case 'GenericObjectTypeAnnotation':
232234
return element;
233235
case 'AnyObjectTypeAnnotation':

packages/react-native-codegen/src/generators/modules/ObjCppUtils/GenerateStructsForConstants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ function getBuilderInputFieldDeclaration(
9696
property.name,
9797
)}::Builder`,
9898
);
99+
case 'TypeAliasTypeAnnotation': // TODO: Handle aliases
99100
case 'GenericObjectTypeAnnotation':
100101
case 'AnyTypeAnnotation':
101102
if (property.optional) {
@@ -185,6 +186,7 @@ function getObjectProperty(property: ObjectParamTypeAnnotation): string {
185186
case 'BooleanTypeAnnotation':
186187
return boolGetter(property.name, property.optional);
187188
case 'StringTypeAnnotation':
189+
case 'TypeAliasTypeAnnotation': // TODO: Handle aliases
188190
case 'GenericObjectTypeAnnotation':
189191
case 'AnyTypeAnnotation':
190192
return safeGetter(property.name, property.optional);

packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const EMPTY_NATIVE_MODULES: SchemaType = {
1717
SampleTurboModule: {
1818
nativeModules: {
1919
SampleTurboModule: {
20+
aliases: {},
2021
properties: [],
2122
},
2223
},
@@ -29,6 +30,7 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
2930
SampleTurboModule: {
3031
nativeModules: {
3132
SampleTurboModule: {
33+
aliases: {},
3234
properties: [
3335
{
3436
name: 'getConstants',
@@ -291,6 +293,7 @@ const TWO_MODULES_SAME_FILE: SchemaType = {
291293
NativeSampleTurboModule: {
292294
nativeModules: {
293295
SampleTurboModule: {
296+
aliases: {},
294297
properties: [
295298
{
296299
name: 'voidFunc',
@@ -307,6 +310,7 @@ const TWO_MODULES_SAME_FILE: SchemaType = {
307310
],
308311
},
309312
Sample2TurboModule: {
313+
aliases: {},
310314
properties: [
311315
{
312316
name: 'voidFunc',
@@ -332,6 +336,7 @@ const TWO_MODULES_DIFFERENT_FILES: SchemaType = {
332336
NativeSampleTurboModule: {
333337
nativeModules: {
334338
SampleTurboModule: {
339+
aliases: {},
335340
properties: [
336341
{
337342
name: 'voidFunc',
@@ -352,6 +357,7 @@ const TWO_MODULES_DIFFERENT_FILES: SchemaType = {
352357
NativeSampleTurboModule2: {
353358
nativeModules: {
354359
Sample2TurboModule: {
360+
aliases: {},
355361
properties: [
356362
{
357363
name: 'getConstants',
@@ -390,6 +396,7 @@ const COMPLEX_OBJECTS: SchemaType = {
390396
NativeSampleTurboModule: {
391397
nativeModules: {
392398
SampleTurboModule: {
399+
aliases: {},
393400
properties: [
394401
{
395402
name: 'difficult',

packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,54 @@ type Num2 = Num;
154154
export type Void = void;
155155
export type A = number;
156156
export type B = number;
157+
export type ObjectAlias = {|
158+
x: number,
159+
y: number,
160+
label: string,
161+
truthy: boolean,
162+
|}
157163
158164
export interface Spec extends TurboModule {
159165
// Exported methods.
160166
+getNumber: Num2;
161167
+getVoid: () => Void;
162168
+getArray: (a: Array<A>) => {| a: B |};
169+
+getStringFromAlias: (a: ObjectAlias) => string;
170+
}
171+
172+
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
173+
174+
`;
175+
176+
const NATIVE_MODULE_WITH_NESTED_ALIASES = `
177+
/**
178+
* Copyright (c) Facebook, Inc. and its affiliates.
179+
*
180+
* This source code is licensed under the MIT license found in the
181+
* LICENSE file in the root directory of this source tree.
182+
*
183+
* @flow strict-local
184+
* @format
185+
*/
186+
187+
'use strict';
188+
189+
import type {TurboModule} from '../RCTExport';
190+
import * as TurboModuleRegistry from '../TurboModuleRegistry';
191+
192+
type Bar = {|
193+
z: number
194+
|};
195+
196+
type Foo = {|
197+
bar1: Bar,
198+
bar2: Bar,
199+
|};
200+
201+
export interface Spec extends TurboModule {
202+
// Exported methods.
203+
foo1: (x: Foo) => void;
204+
foo2: (x: Foo) => void;
163205
}
164206
165207
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
@@ -459,6 +501,7 @@ module.exports = {
459501
NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE,
460502
NATIVE_MODULE_WITH_FLOAT_AND_INT32,
461503
NATIVE_MODULE_WITH_ALIASES,
504+
NATIVE_MODULE_WITH_NESTED_ALIASES,
462505
NATIVE_MODULE_WITH_PROMISE,
463506
NATIVE_MODULE_WITH_COMPLEX_OBJECTS,
464507
NATIVE_MODULE_WITH_COMPLEX_OBJECTS_WITH_NULLABLE_KEY,

0 commit comments

Comments
 (0)