GenerateModuleCpp: Replace string replace with string templates

Summary:
## Benefits:
- Improved Readability
- Improved type-safety with templates

Changelog: [Internal]

Differential Revision: D24386276

fbshipit-source-id: d5913122221960c06c5256af10ace1d2f7a60b49
This commit is contained in:
Ramanpreet Nara
2020-10-19 21:59:29 -07:00
committed by Facebook GitHub Bot
parent de32fd2539
commit 33789ba0ea
@@ -24,32 +24,60 @@ const {unwrapNullable} = require('../../parsers/flow/modules/utils');
type FilesOutput = Map<string, string>;
const propertyHeaderTemplate =
'static jsi::Value __hostFunction_::_HASTE_MODULE_NAME_::CxxSpecJSI_::_PROPERTY_NAME_::(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {';
const HostFunctionTemplate = ({
hasteModuleName,
methodName,
isVoid,
args,
}: $ReadOnly<{
hasteModuleName: string,
methodName: string,
isVoid: boolean,
args: Array<string>,
}>) => {
const methodCallArgs = ['rt', ...args].join(', ');
const methodCall = `static_cast<${hasteModuleName}CxxSpecJSI *>(&turboModule)->${methodName}(${methodCallArgs});`;
const propertyCastTemplate =
'static_cast<::_HASTE_MODULE_NAME_::CxxSpecJSI *>(&turboModule)->::_PROPERTY_NAME_::(rt::_ARGS_::);';
const nonvoidPropertyTemplate = `${propertyHeaderTemplate}
return ${propertyCastTemplate}
}`.trim();
const voidPropertyTemplate = `${propertyHeaderTemplate}
${propertyCastTemplate}
return jsi::Value::undefined();
return `static jsi::Value __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {${
isVoid ? `\n ${methodCall}` : ''
}
return ${isVoid ? 'jsi::Value::undefined();' : methodCall}
}`;
};
const proprertyDefTemplate =
' methodMap_["::_PROPERTY_NAME_::"] = MethodMetadata {::_ARGS_COUNT_::, __hostFunction_::_HASTE_MODULE_NAME_::CxxSpecJSI_::_PROPERTY_NAME_::};';
const ModuleTemplate = ({
hasteModuleName,
hostFunctions,
moduleName,
methods,
}: $ReadOnly<{|
hasteModuleName: string,
hostFunctions: $ReadOnlyArray<string>,
moduleName: string,
methods: $ReadOnlyArray<
$ReadOnly<{|methodName: string, paramCount: number|}>,
>,
|}>) => {
return `${hostFunctions.join('\n')}
const moduleTemplate = `::_MODULE_PROPERTIES_::
${hasteModuleName}CxxSpecJSI::${hasteModuleName}CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
: TurboModule("${moduleName}", jsInvoker) {
${methods
.map(({methodName, paramCount}) => {
return ` methodMap_["${methodName}"] = MethodMetadata {${paramCount}, __hostFunction_${hasteModuleName}CxxSpecJSI_${methodName}};`;
})
.join('\n')}
}`;
};
::_HASTE_MODULE_NAME_::CxxSpecJSI::::_HASTE_MODULE_NAME_::CxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
: TurboModule("::_NATIVE_MODULE_NAME_::", jsInvoker) {
::_PROPERTIES_MAP_::
}`.trim();
const template = `/**
const FileTemplate = ({
libraryName,
modules,
}: $ReadOnly<{
libraryName: string,
modules: string,
}>) => {
return `/**
* ${'C'}opyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
@@ -58,19 +86,20 @@ const template = `/**
* ${'@'}generated by codegen project: GenerateModuleH.js
*/
#include <react/modules/::_LIBRARY_NAME_::/NativeModules.h>
#include <react/modules/${libraryName}/NativeModules.h>
namespace facebook {
namespace react {
::_MODULES_::
${modules}
} // namespace react
} // namespace facebook
`;
};
function traverseArg(
function serializeArg(
arg: NativeModuleMethodParamSchema,
index: number,
resolveAlias: AliasResolver,
@@ -127,7 +156,8 @@ function traverseArg(
}
}
function traverseProperty(
function serializePropertyIntoHostFunction(
hasteModuleName: string,
property: NativeModulePropertySchema,
resolveAlias: AliasResolver,
): string {
@@ -136,16 +166,17 @@ function traverseProperty(
] = unwrapNullable<NativeModuleFunctionTypeAnnotation>(
property.typeAnnotation,
);
const propertyTemplate =
propertyTypeAnnotation.returnTypeAnnotation.type === 'VoidTypeAnnotation'
? voidPropertyTemplate
: nonvoidPropertyTemplate;
const traversedArgs = propertyTypeAnnotation.params
.map((p, i) => traverseArg(p, i, resolveAlias))
.join(', ');
return propertyTemplate
.replace(/::_PROPERTY_NAME_::/g, property.name)
.replace(/::_ARGS_::/g, traversedArgs === '' ? '' : ', ' + traversedArgs);
const isVoid =
propertyTypeAnnotation.returnTypeAnnotation.type === 'VoidTypeAnnotation';
return HostFunctionTemplate({
hasteModuleName,
methodName: property.name,
isVoid,
args: propertyTypeAnnotation.params.map((p, i) =>
serializeArg(p, i, resolveAlias),
),
});
}
module.exports = {
@@ -157,7 +188,7 @@ module.exports = {
const nativeModules = getModules(schema);
const modules = Object.keys(nativeModules)
.map(hasteModuleName => {
.map((hasteModuleName: string) => {
const nativeModule = nativeModules[hasteModuleName];
const {
aliases,
@@ -165,39 +196,37 @@ module.exports = {
moduleNames,
} = nativeModule;
const resolveAlias = createAliasResolver(aliases);
const traversedProperties = properties
.map(property => traverseProperty(property, resolveAlias))
.join('\n');
return (
moduleTemplate
.replace(/::_MODULE_PROPERTIES_::/g, traversedProperties)
// TODO: What happens when there are more than one NativeModule requires?
.replace('::_NATIVE_MODULE_NAME_::', moduleNames[0])
.replace(
'::_PROPERTIES_MAP_::',
properties
.map(
({
name: propertyName,
typeAnnotation: nullableTypeAnnotation,
}) => {
const [{params}] = unwrapNullable(nullableTypeAnnotation);
return proprertyDefTemplate
.replace(/::_PROPERTY_NAME_::/g, propertyName)
.replace(/::_ARGS_COUNT_::/g, params.length.toString());
},
)
.join('\n'),
)
.replace(/::_HASTE_MODULE_NAME_::/g, hasteModuleName)
const hostFunctions = properties.map(property =>
serializePropertyIntoHostFunction(
hasteModuleName,
property,
resolveAlias,
),
);
return ModuleTemplate({
hasteModuleName,
hostFunctions,
// TODO: What happens when there are more than one NativeModule requires?
moduleName: moduleNames[0],
methods: properties.map(
({name: propertyName, typeAnnotation: nullableTypeAnnotation}) => {
const [{params}] = unwrapNullable(nullableTypeAnnotation);
return {
methodName: propertyName,
paramCount: params.length,
};
},
),
});
})
.join('\n');
const fileName = 'NativeModules.cpp';
const replacedTemplate = template
.replace(/::_MODULES_::/g, modules)
.replace(/::_LIBRARY_NAME_::/g, libraryName);
const replacedTemplate = FileTemplate({
modules,
libraryName,
});
return new Map([[fileName, replacedTemplate]]);
},
};