mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Generate Custom Native State (#34796)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5fa51e665f
commit
7490ad4a21
+117
-8
@@ -10,7 +10,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {SchemaType} from '../../CodegenSchema';
|
||||
import type {
|
||||
NamedShape,
|
||||
SchemaType,
|
||||
StateTypeAnnotation,
|
||||
} from '../../CodegenSchema';
|
||||
const {capitalize} = require('../Utils.js');
|
||||
const {getStateConstituents} = require('./ComponentsGeneratorUtils.js');
|
||||
|
||||
// File path -> contents
|
||||
type FilesOutput = Map<string, string>;
|
||||
@@ -21,7 +27,8 @@ const FileTemplate = ({
|
||||
}: {
|
||||
libraryName: string,
|
||||
stateClasses: string,
|
||||
}) => `
|
||||
}) =>
|
||||
`
|
||||
/**
|
||||
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
||||
*
|
||||
@@ -32,6 +39,8 @@ const FileTemplate = ({
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <react/renderer/components/${libraryName}/Props.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <folly/dynamic.h>
|
||||
#include <react/renderer/mapbuffer/MapBuffer.h>
|
||||
@@ -45,13 +54,39 @@ ${stateClasses}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
`;
|
||||
`.trim();
|
||||
|
||||
const StateTemplate = ({stateName}: {stateName: string}) => `
|
||||
const StateTemplate = ({
|
||||
stateName,
|
||||
ctorParams,
|
||||
ctorInits,
|
||||
getters,
|
||||
stateProps,
|
||||
}: {
|
||||
stateName: string,
|
||||
ctorParams: string,
|
||||
ctorInits: string,
|
||||
getters: string,
|
||||
stateProps: string,
|
||||
}) => {
|
||||
let stateWithParams = '';
|
||||
if (ctorParams.length > 0) {
|
||||
stateWithParams = `
|
||||
${stateName}State(
|
||||
${ctorParams}
|
||||
)
|
||||
: ${ctorInits}{};
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
class ${stateName}State {
|
||||
public:
|
||||
${stateWithParams}
|
||||
${stateName}State() = default;
|
||||
|
||||
${getters}
|
||||
|
||||
#ifdef ANDROID
|
||||
${stateName}State(${stateName}State const &previousState, folly::dynamic data){};
|
||||
folly::dynamic getDynamic() const {
|
||||
@@ -61,8 +96,61 @@ class ${stateName}State {
|
||||
return MapBufferBuilder::EMPTY();
|
||||
};
|
||||
#endif
|
||||
|
||||
private:
|
||||
${stateProps}
|
||||
};
|
||||
`;
|
||||
`.trim();
|
||||
};
|
||||
|
||||
function sanitize(stringToSanitize: string, endString: string) {
|
||||
if (stringToSanitize.endsWith(endString)) {
|
||||
return stringToSanitize.slice(0, -1 * endString.length);
|
||||
}
|
||||
return stringToSanitize;
|
||||
}
|
||||
|
||||
function generateStrings(
|
||||
componentName: string,
|
||||
state: $ReadOnlyArray<NamedShape<StateTypeAnnotation>>,
|
||||
): {
|
||||
ctorParams: string,
|
||||
ctorInits: string,
|
||||
getters: string,
|
||||
stateProps: string,
|
||||
} {
|
||||
let ctorParams = '';
|
||||
let ctorInits = '';
|
||||
let getters = '';
|
||||
let stateProps = '';
|
||||
|
||||
state.forEach(stateShape => {
|
||||
const {name, varName, type, defaultValue} = getStateConstituents(
|
||||
componentName,
|
||||
stateShape,
|
||||
);
|
||||
|
||||
ctorParams += ` ${type} ${name},\n`;
|
||||
ctorInits += `${varName}(${name}),\n `;
|
||||
getters += `${type} get${capitalize(name)}() const;\n `;
|
||||
let finalDefaultValue = defaultValue;
|
||||
if (defaultValue.length > 0) {
|
||||
finalDefaultValue = `{${defaultValue}}`;
|
||||
}
|
||||
stateProps += ` ${type} ${varName}${finalDefaultValue};\n `;
|
||||
});
|
||||
|
||||
// Sanitize
|
||||
ctorParams = sanitize(ctorParams.trim(), ',');
|
||||
ctorInits = sanitize(ctorInits.trim(), ',');
|
||||
|
||||
return {
|
||||
ctorParams,
|
||||
ctorInits,
|
||||
getters,
|
||||
stateProps,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generate(
|
||||
@@ -72,6 +160,7 @@ module.exports = {
|
||||
assumeNonnull: boolean = false,
|
||||
): FilesOutput {
|
||||
const fileName = 'States.h';
|
||||
|
||||
const stateClasses = Object.keys(schema.modules)
|
||||
.map(moduleName => {
|
||||
const module = schema.modules[moduleName];
|
||||
@@ -84,14 +173,34 @@ module.exports = {
|
||||
if (components == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.keys(components)
|
||||
.map(componentName => {
|
||||
if (components[componentName].interfaceOnly === true) {
|
||||
const component = components[componentName];
|
||||
if (component.interfaceOnly === true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return StateTemplate({stateName: componentName});
|
||||
const state = component.state;
|
||||
if (!state) {
|
||||
return StateTemplate({
|
||||
stateName: componentName,
|
||||
ctorParams: '',
|
||||
ctorInits: '',
|
||||
getters: '',
|
||||
stateProps: '',
|
||||
});
|
||||
}
|
||||
|
||||
const {ctorParams, ctorInits, getters, stateProps} =
|
||||
generateStrings(componentName, state);
|
||||
|
||||
return StateTemplate({
|
||||
stateName: componentName,
|
||||
ctorParams,
|
||||
ctorInits,
|
||||
getters,
|
||||
stateProps,
|
||||
});
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('\n\n');
|
||||
|
||||
Reference in New Issue
Block a user