diff --git a/packages/react-native-codegen/src/generators/GenerateModuleCpp.js b/packages/react-native-codegen/src/generators/GenerateModuleCpp.js index b27d9fff952..77fe72dd2d3 100644 --- a/packages/react-native-codegen/src/generators/GenerateModuleCpp.js +++ b/packages/react-native-codegen/src/generators/GenerateModuleCpp.js @@ -14,6 +14,35 @@ import type {SchemaType} from '../CodegenSchema'; type FilesOutput = Map; +const propertyHeaderTemplate = + 'static jsi::Value __hostFunction_Native::_MODULE_NAME_::TurboCxxModuleSpecJSI_::_PROPERTY_NAME_::(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {'; + +const propertyCastTemplate = + 'static_cast(&turboModule)->::_PROPERTY_NAME_::(rt::_ARGS_::);'; + +const nonvoidPropertyTemplate = ` +${propertyHeaderTemplate} + return ${propertyCastTemplate} +}`; + +const voidPropertyTemplate = ` +${propertyHeaderTemplate} + ${propertyCastTemplate} + return jsi::Value::undefined(); +}`; + +const proprertyDefTemplate = + ' methodMap_["::_PROPERTY_NAME_::"] = MethodMetadata {::_ARGS_COUNT_::, __hostFunction_Native::_MODULE_NAME_::TurboCxxModuleSpecJSI_::_PROPERTY_NAME_::};'; + +const moduleTemplate = ` +::_MODULE_PROPERTIES_::​ + +Native::_MODULE_NAME_::TurboCxxModuleSpecJSI::Native::_MODULE_NAME_::TurboCxxModuleSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("::_MODULE_NAME_::TurboCxxModule", jsInvoker) { +::_PROPERTIES_MAP_:: +} +`; + const template = ` /** * Copyright (c) Facebook, Inc. and its affiliates. @@ -27,23 +56,94 @@ const template = ` namespace facebook { namespace react { -::_MODULE_PROPERTIES_:: -::_PROPERTIES_MAP_:: +::_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(rt)'); + case 'NumberTypeAnnotation': + case 'FloatTypeAnnotation': + case 'Int32TypeAnnotation': + return wrap('.getNumber(rt)'); + 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 fileName = `${libraryName}.cpp`; + const nativeModules = Object.keys(schema.modules) + .map(moduleName => { + const modules = schema.modules[moduleName].nativeModules; + if (modules == null) { + return null; + } - const moduleProperties = ''; + return modules; + }) + .filter(Boolean) + .reduce((acc, modules) => Object.assign(acc, modules), {}); - const replacedTemplate = template - .replace(/::_MODULE_PROPERTIES_::/g, moduleProperties) - .replace('::_MODULE_NAME_::', libraryName) - .replace('::_PROPERTIES_MAP_::', ''); + 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.slice(0, -11)); // FIXME + }) + .join('\n'); + + const fileName = 'NativeModules.h'; + const replacedTemplate = template.replace(/::_MODULES_::/g, modules); return new Map([[fileName, replacedTemplate]]); }, diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap index 85631b7f0af..5cf7cc6e800 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap @@ -2,7 +2,7 @@ exports[`GenerateModuleCpp can generate fixture EMPTY_NATIVE_MODULES 1`] = ` Map { - "EMPTY_NATIVE_MODULES.cpp" => " + "NativeModules.h" => " /** * Copyright (c) Facebook, Inc. and its affiliates. * @@ -10,12 +10,19 @@ Map { * LICENSE file in the root directory of this source tree. */ -#include \\"NativeEMPTY_NATIVE_MODULESTurboCxxModuleSpecJSI.h\\" +#include \\"Native::_MODULE_NAME_::TurboCxxModuleSpecJSI.h\\" namespace facebook { namespace react { +​ + +NativeSampleTurboCxxModuleSpecJSI::NativeSampleTurboCxxModuleSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboCxxModule\\", jsInvoker) { + +} + } // namespace react @@ -26,7 +33,7 @@ namespace react { exports[`GenerateModuleCpp can generate fixture SIMPLE_NATIVE_MODULES 1`] = ` Map { - "SIMPLE_NATIVE_MODULES.cpp" => " + "NativeModules.h" => " /** * Copyright (c) Facebook, Inc. and its affiliates. * @@ -34,13 +41,70 @@ Map { * LICENSE file in the root directory of this source tree. */ -#include \\"NativeSIMPLE_NATIVE_MODULESTurboCxxModuleSpecJSI.h\\" +#include \\"Native::_MODULE_NAME_::TurboCxxModuleSpecJSI.h\\" namespace facebook { namespace react { +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getConstants(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getConstants(rt); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc(rt); + return jsi::Value::undefined(); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getBool(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getBool(rt, args[0].getBool(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getNumber(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getNumber(rt, args[0].getNumber(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getString(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getString(rt, args[0].getString(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getArray(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getArray(rt, args[0].getObject(rt).getArray(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getObject(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getObject(rt, args[0].getObject(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValue(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValue(rt, args[0].getNumber(rt), args[1].getString(rt), args[2].getObject(rt)); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithCallback(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->getValueWithCallback(rt, std::move(args[0].getObject(rt).getFunction(rt))); + return jsi::Value::undefined(); +} + +static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getValueWithPromise(rt, args[0].getBool(rt)); +}​ + +NativeSampleTurboCxxModuleSpecJSI::NativeSampleTurboCxxModuleSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboCxxModule\\", jsInvoker) { + methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getConstants}; + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_voidFunc}; + methodMap_[\\"getBool\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getBool}; + methodMap_[\\"getNumber\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getNumber}; + methodMap_[\\"getString\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getString}; + methodMap_[\\"getArray\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getArray}; + methodMap_[\\"getObject\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getObject}; + methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValue}; + methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithCallback}; + methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboCxxModuleSpecJSI_getValueWithPromise}; +} + + } // namespace react } // namespace facebook