Summary:
## Misc. Improvements
* We now have 95%+ flow coverage in all generator files. Henceforth, we can make changes to these files with more confidence, and trust flow to catch more errors. This should also improve the DevX of working on these files.
* Better templates: Instead of doing string replace with RegExps, we instead use functions and leverage JS template literals to generate our code. A few benefits: (1) data dependencies of templates are clearly visible, and statically checked by flow, (2) the templates are more readable in VSCode.
* Merged the GenerateModuleHObjCpp.js and GenerateModuleMm.js generators. They can share a lot of logic, so it's not a good idea to keep them separate.
* The ObjC++ module generator no longer generates “dead” structs (i.e structs that aren’t used by type-safety infra). In fact, it explicitly only supports the types in our Wiki. (I know this wasn’t the case with the legacy codegen, because we were generating native code for enums in the legacy codegen). This is a mixed bag. The test to verify correctness will be more difficult to write. However, keeping structs in the codegen needlessly complicates the parsers + generators, and creates technical debt for us to clean up later.
## Abstractions
- **StructCollector:** As we serialize NativeModule methods, when we detect an ObjectTypeAnnotation in the return type of `getConstants()` or inside a method param, we must create a Struct JS object for it. When we detect a type-alias (also in the same locations), we must look up that type-alias and create a Struct from its RHS. A Struct is basically an ObjectTypeAnnotation with a context (i.e: used in getConstants() vs as a method param), that cannot contain other ObjectTypeAnnotations.
- **serializeMethod.js** Given a NativeModule method type annotation, output the protocol method, JS return type, selector, a record of which params were structs, and which structs. Basically, this is all the information necessary to generate the declaration and implementation codegen for a partiular NativeModule method.
- **serializeStruct/*.js**: After creating all these Structs, we need to loop over all of them, and tranform them into ObjC++ code.
- **serializeStruct.js**: Depending on the struct context, calls either `serializeRegularStruct.js` or `serializeConstantsStruct.js`. Both of these files have the same layout/abstractions. They look very similar.
- **serializeModule.js:** Outputs RCTCxxConvert categories for transforming `NSDictionary *` into C++ structs. Outputs ObjCTurboModule subclass.
## Algorithm
```
for spec in NativeModuleSpecs
structCollector = new StructCollector
resolveAlias = (aliasName) => nullthrows(spec.aliases[aliasName])
methodDatas = []
for method in methods(spec)
methodData.push(serializeMethod(method, structCollector, resolveAlias))
end
structs = structCollector.getStructs()
output generateImplCodegen(methodDatas, structs)
output generateHeaderCodegen(methodDatas, structs)
end
```
Changelog: [Internal]
Reviewed By: hramos
Differential Revision: D23633940
fbshipit-source-id: 7c29f458b65434f4865ef1993061b0f0dc7d04ce
Summary:
There are two implementations of `RCTConvertVecToArray`. The first implementation:
```
template<typename ContainerT>
NSArray *RCTConvertVecToArray(const ContainerT &vec, id (^convertor)(typename ContainerT::value_type element))
{
NSMutableArray *array = [NSMutableArray new];
for (size_t i = 0, size = vec.size(); i < size; ++i) {
id object = convertor(vec[i]);
array[i] = object ?: (id)kCFNull;
}
return array;
}
```
The purpose of the second implementation is to default the convertor function to the identify function:
```
template<typename ContainerT>
NSArray *RCTConvertVecToArray(const ContainerT &vec)
{
return RCTConvertVecToArray(vec, ^id(typename ContainerT::value_type element) { return element; });
}
```
Meanwhile, there's only one implementation of `RCTConvertOptionalVecToArray`:
```
template<typename ContainerT>
NSArray *RCTConvertOptionalVecToArray(const folly::Optional<ContainerT> &vec, id (^convertor)(typename ContainerT::value_type element))
{
return vec.hasValue() ? RCTConvertVecToArray(vec.value(), convertor) : nil;
}
```
In this diff, I overload `RCTConvertOptionalVecToArray` to default the convertor to the identify function.
Changelog:
[iOS][Added] - Added RCTConvertOptionalVecToArray with default converter
Reviewed By: PeteTheHeat
Differential Revision: D18148891
fbshipit-source-id: d7d5f05cda06c9fa5374334ec4e9dbbd8b6d2eba
Summary:
When converting an array into a Vec, we should also check whether the array pointer is `kCFNull`.
In TurboModules, when an object's property is mapped to null, we simply do not insert that property into the corresponding `NSDictionary`. This causes the `NSDictionary` lookup to return `nil`. In the legacy infra, it looks like we may insert `kCFNull` into the `NSDictionary`, which will cause the lookup to return `kCFNull`.
Reviewed By: fkgozali
Differential Revision: D17716785
fbshipit-source-id: 62ffbe14aec7040edd6b3ce687769a285b14b5a1
Summary: This is utility for TurboModule codegen for the purpose of typesafety. It is not used anywhere else at the moment.
Reviewed By: cpojer
Differential Revision: D15929957
fbshipit-source-id: ecf68cc98b78bc5b9c2078492b853a677b625eea