Skip to content

Commit 7490ad4

Browse files
cipolleschifacebook-github-bot
authored andcommitted
Generate Custom Native State (#34796)
Summary: Pull Request resolved: #34796 This diff introduces the generation of custom native states using basic types as we do with the Props. To make it work, the custom types are already writte in the Props.h file, therefore the State.h file must import that other file to have access to the required types. This diff adds and updates the tests for the State. ## Changelog [General][Added] - Generate custom Native State Reviewed By: cortinico Differential Revision: D39816763 fbshipit-source-id: 42d1aa9a6df23145f4a46ae8ccfb43d81fa651fb
1 parent 5fa51e6 commit 7490ad4

22 files changed

+8243
-310
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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 {
14+
NamedShape,
15+
PropTypeAnnotation,
16+
StateTypeAnnotation,
17+
} from '../../CodegenSchema';
18+
19+
import type {
20+
StringTypeAnnotation,
21+
ReservedPropTypeAnnotation,
22+
ObjectTypeAnnotation,
23+
Int32TypeAnnotation,
24+
FloatTypeAnnotation,
25+
DoubleTypeAnnotation,
26+
BooleanTypeAnnotation,
27+
} from '../../CodegenSchema';
28+
29+
const {
30+
convertDefaultTypeToString,
31+
getCppTypeForAnnotation,
32+
getEnumMaskName,
33+
getEnumName,
34+
generateStructName,
35+
} = require('./CppHelpers.js');
36+
37+
function getNativeTypeFromAnnotation(
38+
componentName: string,
39+
prop:
40+
| NamedShape<PropTypeAnnotation>
41+
| NamedShape<StateTypeAnnotation>
42+
| {
43+
name: string,
44+
typeAnnotation:
45+
| $FlowFixMe
46+
| DoubleTypeAnnotation
47+
| FloatTypeAnnotation
48+
| BooleanTypeAnnotation
49+
| Int32TypeAnnotation
50+
| StringTypeAnnotation
51+
| ObjectTypeAnnotation<PropTypeAnnotation>
52+
| ReservedPropTypeAnnotation
53+
| {
54+
+default: string,
55+
+options: $ReadOnlyArray<string>,
56+
+type: 'StringEnumTypeAnnotation',
57+
}
58+
| {
59+
+elementType: ObjectTypeAnnotation<PropTypeAnnotation>,
60+
+type: 'ArrayTypeAnnotation',
61+
},
62+
},
63+
nameParts: $ReadOnlyArray<string>,
64+
): string {
65+
const typeAnnotation = prop.typeAnnotation;
66+
67+
switch (typeAnnotation.type) {
68+
case 'BooleanTypeAnnotation':
69+
case 'StringTypeAnnotation':
70+
case 'Int32TypeAnnotation':
71+
case 'DoubleTypeAnnotation':
72+
case 'FloatTypeAnnotation':
73+
return getCppTypeForAnnotation(typeAnnotation.type);
74+
case 'ReservedPropTypeAnnotation':
75+
switch (typeAnnotation.name) {
76+
case 'ColorPrimitive':
77+
return 'SharedColor';
78+
case 'ImageSourcePrimitive':
79+
return 'ImageSource';
80+
case 'PointPrimitive':
81+
return 'Point';
82+
case 'EdgeInsetsPrimitive':
83+
return 'EdgeInsets';
84+
default:
85+
(typeAnnotation.name: empty);
86+
throw new Error('Received unknown ReservedPropTypeAnnotation');
87+
}
88+
case 'ArrayTypeAnnotation': {
89+
const arrayType = typeAnnotation.elementType.type;
90+
if (arrayType === 'ArrayTypeAnnotation') {
91+
return `std::vector<${getNativeTypeFromAnnotation(
92+
componentName,
93+
{typeAnnotation: typeAnnotation.elementType, name: ''},
94+
nameParts.concat([prop.name]),
95+
)}>`;
96+
}
97+
if (arrayType === 'ObjectTypeAnnotation') {
98+
const structName = generateStructName(
99+
componentName,
100+
nameParts.concat([prop.name]),
101+
);
102+
return `std::vector<${structName}>`;
103+
}
104+
if (arrayType === 'StringEnumTypeAnnotation') {
105+
const enumName = getEnumName(componentName, prop.name);
106+
return getEnumMaskName(enumName);
107+
}
108+
const itemAnnotation = getNativeTypeFromAnnotation(
109+
componentName,
110+
{
111+
typeAnnotation: typeAnnotation.elementType,
112+
name: componentName,
113+
},
114+
nameParts.concat([prop.name]),
115+
);
116+
return `std::vector<${itemAnnotation}>`;
117+
}
118+
case 'ObjectTypeAnnotation': {
119+
return generateStructName(componentName, nameParts.concat([prop.name]));
120+
}
121+
case 'StringEnumTypeAnnotation':
122+
return getEnumName(componentName, prop.name);
123+
case 'Int32EnumTypeAnnotation':
124+
return getEnumName(componentName, prop.name);
125+
default:
126+
(typeAnnotation: empty);
127+
throw new Error(
128+
`Received invalid typeAnnotation for ${componentName} prop ${prop.name}, received ${typeAnnotation.type}`,
129+
);
130+
}
131+
}
132+
133+
function getStateConstituents(
134+
componentName: string,
135+
stateShape: NamedShape<StateTypeAnnotation>,
136+
): {
137+
name: string,
138+
varName: string,
139+
type: string,
140+
defaultValue: $FlowFixMe,
141+
} {
142+
const name = stateShape.name;
143+
const varName = `${name}_`;
144+
const type = getNativeTypeFromAnnotation(componentName, stateShape, []);
145+
const defaultValue = convertDefaultTypeToString(componentName, stateShape);
146+
147+
return {
148+
name,
149+
varName,
150+
type,
151+
defaultValue,
152+
};
153+
}
154+
155+
module.exports = {
156+
getNativeTypeFromAnnotation,
157+
getStateConstituents,
158+
};

packages/react-native-codegen/src/generators/components/GeneratePropsH.js

Lines changed: 3 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,12 @@
99
*/
1010

1111
'use strict';
12-
import type {
13-
StringTypeAnnotation,
14-
ReservedPropTypeAnnotation,
15-
ObjectTypeAnnotation,
16-
Int32TypeAnnotation,
17-
FloatTypeAnnotation,
18-
DoubleTypeAnnotation,
19-
ComponentShape,
20-
BooleanTypeAnnotation,
21-
} from '../../CodegenSchema';
12+
import type {ComponentShape} from '../../CodegenSchema';
13+
14+
const {getNativeTypeFromAnnotation} = require('./ComponentsGeneratorUtils.js');
2215

2316
const {
2417
convertDefaultTypeToString,
25-
getCppTypeForAnnotation,
2618
getEnumMaskName,
2719
getEnumName,
2820
toSafeCppString,
@@ -294,101 +286,6 @@ function getClassExtendString(component: ComponentShape): string {
294286
return extendString;
295287
}
296288

297-
function getNativeTypeFromAnnotation(
298-
componentName: string,
299-
prop:
300-
| NamedShape<PropTypeAnnotation>
301-
| {
302-
name: string,
303-
typeAnnotation:
304-
| $FlowFixMe
305-
| DoubleTypeAnnotation
306-
| FloatTypeAnnotation
307-
| BooleanTypeAnnotation
308-
| Int32TypeAnnotation
309-
| StringTypeAnnotation
310-
| ObjectTypeAnnotation<PropTypeAnnotation>
311-
| ReservedPropTypeAnnotation
312-
| {
313-
+default: string,
314-
+options: $ReadOnlyArray<string>,
315-
+type: 'StringEnumTypeAnnotation',
316-
}
317-
| {
318-
+elementType: ObjectTypeAnnotation<PropTypeAnnotation>,
319-
+type: 'ArrayTypeAnnotation',
320-
},
321-
},
322-
nameParts: $ReadOnlyArray<string>,
323-
): string {
324-
const typeAnnotation = prop.typeAnnotation;
325-
326-
switch (typeAnnotation.type) {
327-
case 'BooleanTypeAnnotation':
328-
case 'StringTypeAnnotation':
329-
case 'Int32TypeAnnotation':
330-
case 'DoubleTypeAnnotation':
331-
case 'FloatTypeAnnotation':
332-
return getCppTypeForAnnotation(typeAnnotation.type);
333-
case 'ReservedPropTypeAnnotation':
334-
switch (typeAnnotation.name) {
335-
case 'ColorPrimitive':
336-
return 'SharedColor';
337-
case 'ImageSourcePrimitive':
338-
return 'ImageSource';
339-
case 'PointPrimitive':
340-
return 'Point';
341-
case 'EdgeInsetsPrimitive':
342-
return 'EdgeInsets';
343-
default:
344-
(typeAnnotation.name: empty);
345-
throw new Error('Received unknown ReservedPropTypeAnnotation');
346-
}
347-
case 'ArrayTypeAnnotation': {
348-
const arrayType = typeAnnotation.elementType.type;
349-
if (arrayType === 'ArrayTypeAnnotation') {
350-
return `std::vector<${getNativeTypeFromAnnotation(
351-
componentName,
352-
{typeAnnotation: typeAnnotation.elementType, name: ''},
353-
nameParts.concat([prop.name]),
354-
)}>`;
355-
}
356-
if (arrayType === 'ObjectTypeAnnotation') {
357-
const structName = generateStructName(
358-
componentName,
359-
nameParts.concat([prop.name]),
360-
);
361-
return `std::vector<${structName}>`;
362-
}
363-
if (arrayType === 'StringEnumTypeAnnotation') {
364-
const enumName = getEnumName(componentName, prop.name);
365-
return getEnumMaskName(enumName);
366-
}
367-
const itemAnnotation = getNativeTypeFromAnnotation(
368-
componentName,
369-
{
370-
typeAnnotation: typeAnnotation.elementType,
371-
name: componentName,
372-
},
373-
nameParts.concat([prop.name]),
374-
);
375-
return `std::vector<${itemAnnotation}>`;
376-
}
377-
case 'ObjectTypeAnnotation': {
378-
return generateStructName(componentName, nameParts.concat([prop.name]));
379-
}
380-
case 'StringEnumTypeAnnotation':
381-
return getEnumName(componentName, prop.name);
382-
case 'Int32EnumTypeAnnotation':
383-
return getEnumName(componentName, prop.name);
384-
default:
385-
(typeAnnotation: empty);
386-
throw new Error(
387-
`Received invalid typeAnnotation for ${componentName} prop ${prop.name}, received ${typeAnnotation.type}`,
388-
);
389-
}
390-
}
391-
392289
function convertValueToEnumOption(value: string): string {
393290
return toSafeCppString(value);
394291
}

packages/react-native-codegen/src/generators/components/GenerateStateCpp.js

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,23 @@
1010

1111
'use strict';
1212

13-
import type {SchemaType} from '../../CodegenSchema';
13+
import type {
14+
NamedShape,
15+
SchemaType,
16+
StateTypeAnnotation,
17+
} from '../../CodegenSchema';
18+
const {capitalize} = require('../Utils.js');
19+
const {getStateConstituents} = require('./ComponentsGeneratorUtils.js');
1420

1521
// File path -> contents
1622
type FilesOutput = Map<string, string>;
1723

1824
const FileTemplate = ({
1925
libraryName,
20-
stateClasses,
26+
stateGetters,
2127
}: {
2228
libraryName: string,
23-
stateClasses: string,
29+
stateGetters: string,
2430
}) => `
2531
/**
2632
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
@@ -35,13 +41,32 @@ const FileTemplate = ({
3541
namespace facebook {
3642
namespace react {
3743
38-
${stateClasses}
44+
${stateGetters}
3945
4046
} // namespace react
4147
} // namespace facebook
4248
`;
4349

44-
const StateTemplate = ({stateName}: {stateName: string}) => '';
50+
function generateStrings(
51+
componentName: string,
52+
state: $ReadOnlyArray<NamedShape<StateTypeAnnotation>>,
53+
) {
54+
let getters = '';
55+
state.forEach(stateShape => {
56+
const {name, varName, type} = getStateConstituents(
57+
componentName,
58+
stateShape,
59+
);
60+
61+
getters += `
62+
${type} ${componentName}::get${capitalize(name)}() const {
63+
return ${varName};
64+
}
65+
`;
66+
});
67+
68+
return getters.trim();
69+
}
4570

4671
module.exports = {
4772
generate(
@@ -52,7 +77,7 @@ module.exports = {
5277
): FilesOutput {
5378
const fileName = 'States.cpp';
5479

55-
const stateClasses = Object.keys(schema.modules)
80+
const stateGetters = Object.keys(schema.modules)
5681
.map(moduleName => {
5782
const module = schema.modules[moduleName];
5883
if (module.type !== 'Component') {
@@ -67,12 +92,16 @@ module.exports = {
6792

6893
return Object.keys(components)
6994
.map(componentName => {
70-
if (components[componentName].interfaceOnly === true) {
95+
const component = components[componentName];
96+
if (component.interfaceOnly === true) {
7197
return null;
7298
}
73-
return StateTemplate({
74-
stateName: `${componentName}State`,
75-
});
99+
100+
const state = component.state;
101+
if (!state) {
102+
return '';
103+
}
104+
return generateStrings(componentName, state);
76105
})
77106
.filter(Boolean)
78107
.join('\n');
@@ -82,7 +111,7 @@ module.exports = {
82111

83112
const replacedTemplate = FileTemplate({
84113
libraryName,
85-
stateClasses,
114+
stateGetters,
86115
});
87116

88117
return new Map([[fileName, replacedTemplate]]);

0 commit comments

Comments
 (0)