Files
react-native/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js
T
Michał Osadnik d6722477c4 Add e2e tests skeleton for generated cpp code (#25673)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/25673

This diff add e2e code generator validation. I added proper buck rule which compiles cpp code and test if it really compiles.

While testing I faced few minor issues:

- `getBool` and `getNumber` shouldn't have `rt` param.

- Generators now start considering whole module name instead of sliced part of their name.

- Fixed import structure in generated cpp.

- renamed `jsireact` to `ReactCommon` following D16231697

Reviewed By: rickhanlonii

Differential Revision: D16221277

fbshipit-source-id: aff4011ad52dd5e16546ffdb709d6a751ebfaced
2019-07-17 06:21:48 -07:00

151 lines
4.5 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
import type {SchemaType} from '../../CodegenSchema';
type FilesOutput = Map<string, string>;
const propertyHeaderTemplate =
'static jsi::Value __hostFunction_Native::_MODULE_NAME_::SpecJSI_::_PROPERTY_NAME_::(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {';
const propertyCastTemplate =
'static_cast<Native::_MODULE_NAME_::SpecJSI *>(&turboModule)->::_PROPERTY_NAME_::(rt::_ARGS_::);';
const nonvoidPropertyTemplate = `
${propertyHeaderTemplate}
return ${propertyCastTemplate}
}`.trim();
const voidPropertyTemplate = `
${propertyHeaderTemplate}
${propertyCastTemplate}
return jsi::Value::undefined();
}`;
const proprertyDefTemplate =
' methodMap_["::_PROPERTY_NAME_::"] = MethodMetadata {::_ARGS_COUNT_::, __hostFunction_Native::_MODULE_NAME_::SpecJSI_::_PROPERTY_NAME_::};';
const moduleTemplate = `
::_MODULE_PROPERTIES_::
Native::_MODULE_NAME_::SpecJSI::Native::_MODULE_NAME_::SpecJSI(std::shared_ptr<JSCallInvoker> jsInvoker)
: TurboModule("::_MODULE_NAME_::", jsInvoker) {
::_PROPERTIES_MAP_::
}`.trim();
const template = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <react/modules/::_LIBRARY_NAME_::/NativeModules.h>
namespace facebook {
namespace react {
::_MODULES_::
} // namespace react
} // namespace facebook
`;
function traverseArg(arg, index): string {
function wrap(suffix) {
return `args[${index}]${suffix}`;
}
const type = arg.typeAnnotation.type;
switch (type) {
case 'StringTypeAnnotation':
return wrap('.getString(rt)');
case 'BooleanTypeAnnotation':
return wrap('.getBool()');
case 'NumberTypeAnnotation':
case 'FloatTypeAnnotation':
case 'Int32TypeAnnotation':
return wrap('.getNumber()');
case 'ArrayTypeAnnotation':
return wrap('.getObject(rt).getArray(rt)');
case 'FunctionTypeAnnotation':
return `std::move(${wrap('.getObject(rt).getFunction(rt)')})`;
case 'GenericObjectTypeAnnotation':
case 'ObjectTypeAnnotation':
return wrap('.getObject(rt)');
case 'AnyTypeAnnotation':
throw new Error(`Any type is not allowed in params for "${arg.name}"`);
default:
(type: empty);
throw new Error(`Unknown prop type for "${arg.name}, found: ${type}"`);
}
}
function traverseProprety(property): string {
const propertyTemplate =
property.typeAnnotation.returnTypeAnnotation.type === 'VoidTypeAnnotation'
? voidPropertyTemplate
: nonvoidPropertyTemplate;
const traversedArgs = property.typeAnnotation.params
.map(traverseArg)
.join(', ');
return propertyTemplate
.replace(/::_PROPERTY_NAME_::/g, property.name)
.replace(/::_ARGS_::/g, traversedArgs === '' ? '' : ', ' + traversedArgs);
}
module.exports = {
generate(libraryName: string, schema: SchemaType): FilesOutput {
const nativeModules = Object.keys(schema.modules)
.map(moduleName => {
const modules = schema.modules[moduleName].nativeModules;
if (modules == null) {
return null;
}
return modules;
})
.filter(Boolean)
.reduce((acc, modules) => Object.assign(acc, modules), {});
const modules = Object.keys(nativeModules)
.map(name => {
const {properties} = nativeModules[name];
const traversedProperties = properties
.map(property => traverseProprety(property))
.join('\n');
return moduleTemplate
.replace(/::_MODULE_PROPERTIES_::/g, traversedProperties)
.replace(
'::_PROPERTIES_MAP_::',
properties
.map(({name: propertyName, typeAnnotation: {params}}) =>
proprertyDefTemplate
.replace(/::_PROPERTY_NAME_::/g, propertyName)
.replace(/::_ARGS_COUNT_::/g, params.length.toString()),
)
.join('\n'),
)
.replace(/::_MODULE_NAME_::/g, name);
})
.join('\n');
const fileName = 'NativeModules.cpp';
const replacedTemplate = template
.replace(/::_MODULES_::/g, modules)
.replace(/::_LIBRARY_NAME_::/g, libraryName);
return new Map([[fileName, replacedTemplate]]);
},
};