Add generating Cpp from schema json

Summary:
Add generating cpp files following NativeModuleSpec.

We still need to figure out how to deal with module names, so I currently made in workable by extracting `Sample` from `SampleNativeModule` and filing into proper places, but it's a temporary solution.

Reviewed By: rickhanlonii

Differential Revision: D16181292

fbshipit-source-id: 0f50352d7610f99f0228045ae78309383d3e8bfa
This commit is contained in:
Michał Osadnik
2019-07-11 12:36:42 -07:00
committed by Facebook Github Bot
parent 859deb97f6
commit 2bc6e28d17
2 changed files with 176 additions and 12 deletions
@@ -14,6 +14,35 @@ import type {SchemaType} from '../CodegenSchema';
type FilesOutput = Map<string, string>;
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<Native::_MODULE_NAME_::TurboCxxModuleSpecJSI *>(&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<JSCallInvoker> 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]]);
},
@@ -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<JSCallInvoker> 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<NativeSampleTurboCxxModuleSpecJSI *>(&turboModule)->getConstants(rt);
}
static jsi::Value __hostFunction_NativeSampleTurboCxxModuleSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
static_cast<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&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<NativeSampleTurboCxxModuleSpecJSI *>(&turboModule)->getValueWithPromise(rt, args[0].getBool(rt));
}
NativeSampleTurboCxxModuleSpecJSI::NativeSampleTurboCxxModuleSpecJSI(std::shared_ptr<JSCallInvoker> 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