Skip to content

Commit e102592

Browse files
christophpurrermeta-codesync[bot]
authored andcommitted
Deduplicate toObjCType function in struct serializers (#56050)
Summary: Pull Request resolved: #56050 Removes ~75 lines of duplicated `toObjCType` logic between `serializeConstantsStruct.js` and `serializeRegularStruct.js` by extracting it into a new shared module `serializeStructUtils.js`. The two implementations were identical except for array wrapper types (`std::vector` vs `facebook::react::LazyVector`) and type alias suffixes (`::Builder` vs none), which are now handled via a `structContext` parameter that distinguishes between `CONSTANTS` and `REGULAR` contexts. Changelog: [internal] Reviewed By: philIip Differential Revision: D95908134 fbshipit-source-id: c511958c40bf62fd970036f40f6575d8150c32df
1 parent 3d119ac commit e102592

4 files changed

Lines changed: 144 additions & 170 deletions

File tree

packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const {
4242
parseValidUnionType,
4343
} = require('../../Utils');
4444

45-
type StructContext = 'CONSTANTS' | 'REGULAR';
45+
export type StructContext = 'CONSTANTS' | 'REGULAR';
4646

4747
export type RegularStruct = Readonly<{
4848
context: 'REGULAR',

packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js

Lines changed: 13 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,8 @@ import type {ConstantsStruct, StructTypeAnnotation} from '../StructCollector';
1515
import type {StructSerilizationOutput} from './serializeStruct';
1616

1717
const {unwrapNullable} = require('../../../../parsers/parsers-commons');
18-
const {wrapOptional: wrapCxxOptional} = require('../../../TypeUtils/Cxx');
19-
const {
20-
wrapOptional: wrapObjCOptional,
21-
} = require('../../../TypeUtils/Objective-C');
22-
const {capitalize} = require('../../../Utils');
23-
const {getNamespacedStructName, getSafePropertyName} = require('../Utils');
18+
const {getSafePropertyName} = require('../Utils');
19+
const {toObjCType} = require('./serializeStructUtils');
2420

2521
const StructTemplate = ({
2622
hasteModuleName,
@@ -78,84 +74,6 @@ inline JS::${hasteModuleName}::${structName}::Builder::Builder(${structName} i)
7874
return i.unsafeRawValue();
7975
}) {}`;
8076

81-
function toObjCType(
82-
hasteModuleName: string,
83-
nullableTypeAnnotation: Nullable<StructTypeAnnotation>,
84-
isOptional: boolean = false,
85-
): string {
86-
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
87-
const isRequired = !nullable && !isOptional;
88-
89-
switch (typeAnnotation.type) {
90-
case 'ReservedTypeAnnotation':
91-
switch (typeAnnotation.name) {
92-
case 'RootTag':
93-
return wrapCxxOptional('double', isRequired);
94-
default:
95-
(typeAnnotation.name: empty);
96-
throw new Error(`Unknown prop type, found: ${typeAnnotation.name}"`);
97-
}
98-
case 'StringTypeAnnotation':
99-
return 'NSString *';
100-
case 'StringLiteralTypeAnnotation':
101-
return 'NSString *';
102-
case 'UnionTypeAnnotation':
103-
// TODO(T247151345): Implement proper heterogeneous union support. This is unsafe.
104-
return 'NSObject *';
105-
case 'NumberTypeAnnotation':
106-
return wrapCxxOptional('double', isRequired);
107-
case 'NumberLiteralTypeAnnotation':
108-
return wrapCxxOptional('double', isRequired);
109-
case 'FloatTypeAnnotation':
110-
return wrapCxxOptional('double', isRequired);
111-
case 'Int32TypeAnnotation':
112-
return wrapCxxOptional('double', isRequired);
113-
case 'DoubleTypeAnnotation':
114-
return wrapCxxOptional('double', isRequired);
115-
case 'BooleanTypeAnnotation':
116-
return wrapCxxOptional('bool', isRequired);
117-
case 'BooleanLiteralTypeAnnotation':
118-
return wrapCxxOptional('bool', isRequired);
119-
case 'EnumDeclaration':
120-
switch (typeAnnotation.memberType) {
121-
case 'NumberTypeAnnotation':
122-
return wrapCxxOptional('double', isRequired);
123-
case 'StringTypeAnnotation':
124-
return 'NSString *';
125-
default:
126-
throw new Error(
127-
`Couldn't convert enum into ObjC type: ${typeAnnotation.type}"`,
128-
);
129-
}
130-
case 'GenericObjectTypeAnnotation':
131-
return wrapObjCOptional('id<NSObject>', isRequired);
132-
case 'ArrayTypeAnnotation':
133-
if (typeAnnotation.elementType.type === 'AnyTypeAnnotation') {
134-
return wrapObjCOptional('id<NSObject>', isRequired);
135-
}
136-
137-
return wrapCxxOptional(
138-
`std::vector<${toObjCType(
139-
hasteModuleName,
140-
typeAnnotation.elementType,
141-
)}>`,
142-
isRequired,
143-
);
144-
case 'TypeAliasTypeAnnotation':
145-
const structName = capitalize(typeAnnotation.name);
146-
const namespacedStructName = getNamespacedStructName(
147-
hasteModuleName,
148-
structName,
149-
);
150-
return wrapCxxOptional(`${namespacedStructName}::Builder`, isRequired);
151-
default:
152-
(typeAnnotation.type: empty);
153-
throw new Error(
154-
`Couldn't convert into ObjC type: ${typeAnnotation.type}"`,
155-
);
156-
}
157-
}
158-
15977
function toObjCValue(
16078
hasteModuleName: string,
16179
nullableTypeAnnotation: Nullable<StructTypeAnnotation>,
@@ -223,7 +141,11 @@ function toObjCValue(
223141
}
224142

225143
const localVarName = `el${'_'.repeat(depth + 1)}`;
226-
const elementObjCType = toObjCType(hasteModuleName, elementType);
144+
const elementObjCType = toObjCType(
145+
hasteModuleName,
146+
elementType,
147+
'CONSTANTS',
148+
);
227149
const elementObjCValue = toObjCValue(
228150
hasteModuleName,
229151
elementType,
@@ -263,7 +185,12 @@ function serializeConstantsStruct(
263185
.map(property => {
264186
const {typeAnnotation, optional} = property;
265187
const safePropName = getSafePropertyName(property);
266-
const objCType = toObjCType(hasteModuleName, typeAnnotation, optional);
188+
const objCType = toObjCType(
189+
hasteModuleName,
190+
typeAnnotation,
191+
'CONSTANTS',
192+
optional,
193+
);
267194

268195
if (!optional) {
269196
return `RCTRequired<${objCType}> ${safePropName};`;

packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js

Lines changed: 13 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,9 @@ import type {RegularStruct, StructTypeAnnotation} from '../StructCollector';
1515
import type {StructSerilizationOutput} from './serializeStruct';
1616

1717
const {unwrapNullable} = require('../../../../parsers/parsers-commons');
18-
const {wrapOptional: wrapCxxOptional} = require('../../../TypeUtils/Cxx');
19-
const {
20-
wrapOptional: wrapObjCOptional,
21-
} = require('../../../TypeUtils/Objective-C');
2218
const {capitalize} = require('../../../Utils');
2319
const {getNamespacedStructName, getSafePropertyName} = require('../Utils');
20+
const {toObjCType} = require('./serializeStructUtils');
2421

2522
const StructTemplate = ({
2623
hasteModuleName,
@@ -66,83 +63,6 @@ const MethodTemplate = ({
6663
return ${returnValue};
6764
}`;
6865

69-
function toObjCType(
70-
hasteModuleName: string,
71-
nullableTypeAnnotation: Nullable<StructTypeAnnotation>,
72-
isOptional: boolean = false,
73-
): string {
74-
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
75-
const isRequired = !nullable && !isOptional;
76-
77-
switch (typeAnnotation.type) {
78-
case 'ReservedTypeAnnotation':
79-
switch (typeAnnotation.name) {
80-
case 'RootTag':
81-
return wrapCxxOptional('double', isRequired);
82-
default:
83-
(typeAnnotation.name: empty);
84-
throw new Error(`Unknown prop type, found: ${typeAnnotation.name}"`);
85-
}
86-
case 'StringTypeAnnotation':
87-
return 'NSString *';
88-
case 'StringLiteralTypeAnnotation':
89-
return 'NSString *';
90-
case 'UnionTypeAnnotation':
91-
// TODO(T247151345): Implement proper heterogeneous union support. This is unsafe.
92-
return 'NSObject *';
93-
case 'NumberTypeAnnotation':
94-
return wrapCxxOptional('double', isRequired);
95-
case 'NumberLiteralTypeAnnotation':
96-
return wrapCxxOptional('double', isRequired);
97-
case 'FloatTypeAnnotation':
98-
return wrapCxxOptional('double', isRequired);
99-
case 'Int32TypeAnnotation':
100-
return wrapCxxOptional('double', isRequired);
101-
case 'DoubleTypeAnnotation':
102-
return wrapCxxOptional('double', isRequired);
103-
case 'BooleanTypeAnnotation':
104-
return wrapCxxOptional('bool', isRequired);
105-
case 'BooleanLiteralTypeAnnotation':
106-
return wrapCxxOptional('bool', isRequired);
107-
case 'EnumDeclaration':
108-
switch (typeAnnotation.memberType) {
109-
case 'NumberTypeAnnotation':
110-
return wrapCxxOptional('double', isRequired);
111-
case 'StringTypeAnnotation':
112-
return 'NSString *';
113-
default:
114-
throw new Error(
115-
`Couldn't convert enum into ObjC type: ${typeAnnotation.type}"`,
116-
);
117-
}
118-
case 'GenericObjectTypeAnnotation':
119-
return wrapObjCOptional('id<NSObject>', isRequired);
120-
case 'ArrayTypeAnnotation':
121-
if (typeAnnotation.elementType.type === 'AnyTypeAnnotation') {
122-
return wrapObjCOptional('id<NSObject>', isRequired);
123-
}
124-
return wrapCxxOptional(
125-
`facebook::react::LazyVector<${toObjCType(
126-
hasteModuleName,
127-
typeAnnotation.elementType,
128-
)}>`,
129-
isRequired,
130-
);
131-
case 'TypeAliasTypeAnnotation':
132-
const structName = capitalize(typeAnnotation.name);
133-
const namespacedStructName = getNamespacedStructName(
134-
hasteModuleName,
135-
structName,
136-
);
137-
return wrapCxxOptional(namespacedStructName, isRequired);
138-
default:
139-
(typeAnnotation.type: empty);
140-
throw new Error(
141-
`Couldn't convert into ObjC type: ${typeAnnotation.type}"`,
142-
);
143-
}
144-
}
145-
14666
function toObjCValue(
14767
hasteModuleName: string,
14868
nullableTypeAnnotation: Nullable<StructTypeAnnotation>,
@@ -212,7 +132,11 @@ function toObjCValue(
212132
}
213133

214134
const localVarName = `itemValue_${depth}`;
215-
const elementObjCType = toObjCType(hasteModuleName, elementType);
135+
const elementObjCType = toObjCType(
136+
hasteModuleName,
137+
elementType,
138+
'REGULAR',
139+
);
216140
const elementObjCValue = toObjCValue(
217141
hasteModuleName,
218142
elementType,
@@ -256,6 +180,7 @@ function serializeRegularStruct(
256180
const returnType = toObjCType(
257181
hasteModuleName,
258182
typeAnnotation,
183+
'REGULAR',
259184
optional,
260185
);
261186

@@ -270,7 +195,12 @@ function serializeRegularStruct(
270195
.map<string>(property => {
271196
const {typeAnnotation, optional, name: propName} = property;
272197
const safePropertyName = getSafePropertyName(property);
273-
const returnType = toObjCType(hasteModuleName, typeAnnotation, optional);
198+
const returnType = toObjCType(
199+
hasteModuleName,
200+
typeAnnotation,
201+
'REGULAR',
202+
optional,
203+
);
274204
const returnValue = toObjCValue(
275205
hasteModuleName,
276206
typeAnnotation,
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict
8+
* @format
9+
*/
10+
11+
'use strict';
12+
13+
import type {Nullable} from '../../../../CodegenSchema';
14+
import type {StructContext, StructTypeAnnotation} from '../StructCollector';
15+
16+
const {unwrapNullable} = require('../../../../parsers/parsers-commons');
17+
const {wrapOptional: wrapCxxOptional} = require('../../../TypeUtils/Cxx');
18+
const {
19+
wrapOptional: wrapObjCOptional,
20+
} = require('../../../TypeUtils/Objective-C');
21+
const {capitalize} = require('../../../Utils');
22+
const {getNamespacedStructName} = require('../Utils');
23+
24+
function toObjCType(
25+
hasteModuleName: string,
26+
nullableTypeAnnotation: Nullable<StructTypeAnnotation>,
27+
structContext: StructContext,
28+
isOptional: boolean = false,
29+
): string {
30+
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
31+
const isRequired = !nullable && !isOptional;
32+
33+
switch (typeAnnotation.type) {
34+
case 'ReservedTypeAnnotation':
35+
switch (typeAnnotation.name) {
36+
case 'RootTag':
37+
return wrapCxxOptional('double', isRequired);
38+
default:
39+
(typeAnnotation.name: empty);
40+
throw new Error(`Unknown prop type, found: ${typeAnnotation.name}"`);
41+
}
42+
case 'StringTypeAnnotation':
43+
return 'NSString *';
44+
case 'StringLiteralTypeAnnotation':
45+
return 'NSString *';
46+
case 'UnionTypeAnnotation':
47+
// TODO(T247151345): Implement proper heterogeneous union support. This is unsafe.
48+
return 'NSObject *';
49+
case 'NumberTypeAnnotation':
50+
return wrapCxxOptional('double', isRequired);
51+
case 'NumberLiteralTypeAnnotation':
52+
return wrapCxxOptional('double', isRequired);
53+
case 'FloatTypeAnnotation':
54+
return wrapCxxOptional('double', isRequired);
55+
case 'Int32TypeAnnotation':
56+
return wrapCxxOptional('double', isRequired);
57+
case 'DoubleTypeAnnotation':
58+
return wrapCxxOptional('double', isRequired);
59+
case 'BooleanTypeAnnotation':
60+
return wrapCxxOptional('bool', isRequired);
61+
case 'BooleanLiteralTypeAnnotation':
62+
return wrapCxxOptional('bool', isRequired);
63+
case 'EnumDeclaration':
64+
switch (typeAnnotation.memberType) {
65+
case 'NumberTypeAnnotation':
66+
return wrapCxxOptional('double', isRequired);
67+
case 'StringTypeAnnotation':
68+
return 'NSString *';
69+
default:
70+
throw new Error(
71+
`Couldn't convert enum into ObjC type: ${typeAnnotation.type}"`,
72+
);
73+
}
74+
case 'GenericObjectTypeAnnotation':
75+
return wrapObjCOptional('id<NSObject>', isRequired);
76+
case 'ArrayTypeAnnotation':
77+
if (typeAnnotation.elementType.type === 'AnyTypeAnnotation') {
78+
return wrapObjCOptional('id<NSObject>', isRequired);
79+
}
80+
81+
return wrapCxxOptional(
82+
structContext === 'CONSTANTS'
83+
? `std::vector<${toObjCType(
84+
hasteModuleName,
85+
typeAnnotation.elementType,
86+
structContext,
87+
)}>`
88+
: `facebook::react::LazyVector<${toObjCType(
89+
hasteModuleName,
90+
typeAnnotation.elementType,
91+
structContext,
92+
)}>`,
93+
isRequired,
94+
);
95+
case 'TypeAliasTypeAnnotation':
96+
const structName = capitalize(typeAnnotation.name);
97+
const namespacedStructName = getNamespacedStructName(
98+
hasteModuleName,
99+
structName,
100+
);
101+
return wrapCxxOptional(
102+
structContext === 'CONSTANTS'
103+
? `${namespacedStructName}::Builder`
104+
: namespacedStructName,
105+
isRequired,
106+
);
107+
default:
108+
(typeAnnotation.type: empty);
109+
throw new Error(
110+
`Couldn't convert into ObjC type: ${typeAnnotation.type}"`,
111+
);
112+
}
113+
}
114+
115+
module.exports = {
116+
toObjCType,
117+
};

0 commit comments

Comments
 (0)