Skip to content

Commit

Permalink
Add ImageSource and ImageRequest to generate custom NativeState
Browse files Browse the repository at this point in the history
Summary:
This Diff adds supports on the CustomState generation for ImageSource and ImageRequests, to enable NativeComponents to use the ImageSource loading provided by React Native.

To achieve this, I also had to fox some errors in the imports and to introduce some functions to decorate parameters.

This diff also introduces the tests for thise additional types in both generators and parsers.

## Changelog
[General][Added] - add support for ImageSource and ImageRequest in the State.

Differential Revision: https://internalfb.com/D39884889

fbshipit-source-id: c2921db68090ca506642f874b24128015811c7d7
  • Loading branch information
Riccardo Cipolleschi authored and facebook-github-bot committed Oct 9, 2022
1 parent b8b2aed commit 6b58dc3
Show file tree
Hide file tree
Showing 34 changed files with 1,832 additions and 874 deletions.
3 changes: 2 additions & 1 deletion packages/react-native-codegen/src/CodegenSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ export type ReservedPropTypeAnnotation = $ReadOnly<{
| 'ColorPrimitive'
| 'ImageSourcePrimitive'
| 'PointPrimitive'
| 'EdgeInsetsPrimitive',
| 'EdgeInsetsPrimitive'
| 'ImageRequestPrimitive',
}>;

export type StateTypeAnnotation = PropTypeAnnotation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const {
getEnumMaskName,
getEnumName,
generateStructName,
getImports,
} = require('./CppHelpers.js');

function getNativeTypeFromAnnotation(
Expand Down Expand Up @@ -77,6 +78,8 @@ function getNativeTypeFromAnnotation(
return 'SharedColor';
case 'ImageSourcePrimitive':
return 'ImageSource';
case 'ImageRequestPrimitive':
return 'ImageRequest';
case 'PointPrimitive':
return 'Point';
case 'EdgeInsetsPrimitive':
Expand Down Expand Up @@ -152,7 +155,181 @@ function getStateConstituents(
};
}

/// This function process some types if we need to customize them
/// For example, the ImageSource and the reserved types could be trasformed into
/// const address instead of using them as plain types.
function convertTypesToConstAddressIfNeeded(
type: string,
convertibleTypes: Set<string>,
): string {
if (convertibleTypes.has(type)) {
return `${type} const &`;
}
return type;
}

function convertValueToSharedPointerWithMove(
type: string,
value: string,
convertibleTypes: Set<string>,
): string {
if (convertibleTypes.has(type)) {
return `std::make_shared<${type}>(std::move(${value}))`;
}
return value;
}

function convertVariableToSharedPointer(
type: string,
convertibleTypes: Set<string>,
): string {
if (convertibleTypes.has(type)) {
return `std::shared_ptr<${type}>`;
}
return type;
}

function convertVariableToPointer(
type: string,
value: string,
convertibleTypes: Set<string>,
): string {
if (convertibleTypes.has(type)) {
return `*${value}`;
}
return value;
}

const convertCtorParamToAddressType = (type: string): string => {
const typesToConvert: Set<string> = new Set();
typesToConvert.add('ImageSource');

return convertTypesToConstAddressIfNeeded(type, typesToConvert);
};

const convertCtorInitToSharedPointers = (
type: string,
value: string,
): string => {
const typesToConvert: Set<string> = new Set();
typesToConvert.add('ImageRequest');

return convertValueToSharedPointerWithMove(type, value, typesToConvert);
};

const convertGettersReturnTypeToAddressType = (type: string): string => {
const typesToConvert: Set<string> = new Set();
typesToConvert.add('ImageRequest');

return convertTypesToConstAddressIfNeeded(type, typesToConvert);
};

const convertVarTypeToSharedPointer = (type: string): string => {
const typesToConvert: Set<string> = new Set();
typesToConvert.add('ImageRequest');

return convertVariableToSharedPointer(type, typesToConvert);
};

const convertVarValueToPointer = (type: string, value: string): string => {
const typesToConvert: Set<string> = new Set();
typesToConvert.add('ImageRequest');

return convertVariableToPointer(type, value, typesToConvert);
};

function getLocalImports(
properties:
| $ReadOnlyArray<NamedShape<PropTypeAnnotation>>
| $ReadOnlyArray<NamedShape<StateTypeAnnotation>>,
): Set<string> {
const imports: Set<string> = new Set();

function addImportsForNativeName(
name:
| 'ColorPrimitive'
| 'EdgeInsetsPrimitive'
| 'ImageSourcePrimitive'
| 'PointPrimitive'
| 'ImageRequestPrimitive',
) {
switch (name) {
case 'ColorPrimitive':
imports.add('#include <react/renderer/graphics/Color.h>');
return;
case 'ImageSourcePrimitive':
imports.add('#include <react/renderer/imagemanager/primitives.h>');
return;
case 'ImageRequestPrimitive':
imports.add('#include <react/renderer/imagemanager/ImageRequest.h>');
return;
case 'PointPrimitive':
imports.add('#include <react/renderer/graphics/Geometry.h>');
return;
case 'EdgeInsetsPrimitive':
imports.add('#include <react/renderer/graphics/Geometry.h>');
return;
default:
(name: empty);
throw new Error(`Invalid ReservedPropTypeAnnotation name, got ${name}`);
}
}

properties.forEach(prop => {
const typeAnnotation = prop.typeAnnotation;

if (typeAnnotation.type === 'ReservedPropTypeAnnotation') {
addImportsForNativeName(typeAnnotation.name);
}

if (typeAnnotation.type === 'ArrayTypeAnnotation') {
imports.add('#include <vector>');
if (typeAnnotation.elementType.type === 'StringEnumTypeAnnotation') {
imports.add('#include <cinttypes>');
}
}

if (
typeAnnotation.type === 'ArrayTypeAnnotation' &&
typeAnnotation.elementType.type === 'ReservedPropTypeAnnotation'
) {
addImportsForNativeName(typeAnnotation.elementType.name);
}

if (
typeAnnotation.type === 'ArrayTypeAnnotation' &&
typeAnnotation.elementType.type === 'ObjectTypeAnnotation'
) {
const objectProps = typeAnnotation.elementType.properties;
const objectImports = getImports(objectProps);
const localImports = getLocalImports(objectProps);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
objectImports.forEach(imports.add, imports);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
localImports.forEach(imports.add, imports);
}

if (typeAnnotation.type === 'ObjectTypeAnnotation') {
imports.add('#include <react/renderer/core/propsConversions.h>');
const objectImports = getImports(typeAnnotation.properties);
const localImports = getLocalImports(typeAnnotation.properties);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
objectImports.forEach(imports.add, imports);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
localImports.forEach(imports.add, imports);
}
});

return imports;
}

module.exports = {
getNativeTypeFromAnnotation,
getStateConstituents,
convertCtorParamToAddressType,
convertGettersReturnTypeToAddressType,
convertCtorInitToSharedPointers,
convertVarTypeToSharedPointer,
convertVarValueToPointer,
getLocalImports,
};
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function getImports(
name:
| 'ColorPrimitive'
| 'EdgeInsetsPrimitive'
| 'ImageRequestPrimitive'
| 'ImageSourcePrimitive'
| 'PointPrimitive',
) {
Expand All @@ -71,6 +72,8 @@ function getImports(
return;
case 'EdgeInsetsPrimitive':
return;
case 'ImageRequestPrimitive':
return;
case 'ImageSourcePrimitive':
imports.add('#include <react/renderer/components/image/conversions.h>');
return;
Expand Down Expand Up @@ -163,6 +166,8 @@ function convertDefaultTypeToString(
return '';
case 'ImageSourcePrimitive':
return '';
case 'ImageRequestPrimitive':
return '';
case 'PointPrimitive':
return '';
case 'EdgeInsetsPrimitive':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@
'use strict';
import type {ComponentShape} from '../../CodegenSchema';

const {getNativeTypeFromAnnotation} = require('./ComponentsGeneratorUtils.js');
const {
getNativeTypeFromAnnotation,
getLocalImports,
} = require('./ComponentsGeneratorUtils.js');

const {
convertDefaultTypeToString,
getEnumMaskName,
getEnumName,
toSafeCppString,
generateStructName,
getImports,
toIntEnumValueName,
} = require('./CppHelpers.js');

Expand Down Expand Up @@ -500,85 +502,6 @@ function getExtendsImports(
return imports;
}

function getLocalImports(
properties: $ReadOnlyArray<NamedShape<PropTypeAnnotation>>,
): Set<string> {
const imports: Set<string> = new Set();

function addImportsForNativeName(
name:
| 'ColorPrimitive'
| 'EdgeInsetsPrimitive'
| 'ImageSourcePrimitive'
| 'PointPrimitive',
) {
switch (name) {
case 'ColorPrimitive':
imports.add('#include <react/renderer/graphics/Color.h>');
return;
case 'ImageSourcePrimitive':
imports.add('#include <react/renderer/imagemanager/primitives.h>');
return;
case 'PointPrimitive':
imports.add('#include <react/renderer/graphics/Geometry.h>');
return;
case 'EdgeInsetsPrimitive':
imports.add('#include <react/renderer/graphics/Geometry.h>');
return;
default:
(name: empty);
throw new Error(`Invalid ReservedPropTypeAnnotation name, got ${name}`);
}
}

properties.forEach(prop => {
const typeAnnotation = prop.typeAnnotation;

if (typeAnnotation.type === 'ReservedPropTypeAnnotation') {
addImportsForNativeName(typeAnnotation.name);
}

if (typeAnnotation.type === 'ArrayTypeAnnotation') {
imports.add('#include <vector>');
if (typeAnnotation.elementType.type === 'StringEnumTypeAnnotation') {
imports.add('#include <cinttypes>');
}
}

if (
typeAnnotation.type === 'ArrayTypeAnnotation' &&
typeAnnotation.elementType.type === 'ReservedPropTypeAnnotation'
) {
addImportsForNativeName(typeAnnotation.elementType.name);
}

if (
typeAnnotation.type === 'ArrayTypeAnnotation' &&
typeAnnotation.elementType.type === 'ObjectTypeAnnotation'
) {
const objectProps = typeAnnotation.elementType.properties;
const objectImports = getImports(objectProps);
const localImports = getLocalImports(objectProps);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
objectImports.forEach(imports.add, imports);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
localImports.forEach(imports.add, imports);
}

if (typeAnnotation.type === 'ObjectTypeAnnotation') {
imports.add('#include <react/renderer/core/propsConversions.h>');
const objectImports = getImports(typeAnnotation.properties);
const localImports = getLocalImports(typeAnnotation.properties);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
objectImports.forEach(imports.add, imports);
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
localImports.forEach(imports.add, imports);
}
});

return imports;
}

function generateStructsForComponent(
componentName: string,
component: ComponentShape,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ function getJavaValueForProp(
return 'ColorPropConverter.getColor(value, view.getContext())';
case 'ImageSourcePrimitive':
return '(ReadableMap) value';
case 'ImageRequestPrimitive':
return '(ReadableMap) value';
case 'PointPrimitive':
return '(ReadableMap) value';
case 'EdgeInsetsPrimitive':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ function getJavaValueForProp(
case 'ImageSourcePrimitive':
addNullable(imports);
return '@Nullable ReadableMap value';
case 'ImageRequestPrimitive':
addNullable(imports);
return '@Nullable ReadableMap value';
case 'PointPrimitive':
addNullable(imports);
return '@Nullable ReadableMap value';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ function toJavaType(
importReadableMap();
return '@Nullable ReadableMap';

// TODO: Make ImageRequestPrimitive type-safe
case 'ImageRequestPrimitive':
importNullable();
importReadableMap();
return '@Nullable ReadableMap';

// TODO: Make PointPrimitive type-safe
case 'PointPrimitive':
importNullable();
Expand Down Expand Up @@ -162,6 +168,11 @@ function toJavaType(
importReadableMap();
return 'ReadableMap';

// TODO: Make ImageRequestPrimitive type-safe
case 'ImageRequestPrimitive':
importReadableMap();
return 'ReadableMap';

// TODO: Make PointPrimitive type-safe
case 'PointPrimitive':
importReadableMap();
Expand Down
Loading

0 comments on commit 6b58dc3

Please sign in to comment.