Skip to content

Commit

Permalink
Introduce TypeUtils (facebook#42122)
Browse files Browse the repository at this point in the history
Summary:

This diff introduces the `TypeUtils` directory where we can put platform-specific, context-independent type transformations.

Changelog: [Internal]

Differential Revision: D52291837
  • Loading branch information
dmytrorykun authored and facebook-github-bot committed Jan 3, 2024
1 parent b81a081 commit 7497df7
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ namespace JS {
struct Builder {
struct Input {
std::optional<bool> D;
id<NSObject> _Nullable A;
id<NSObject> _Nullable A;
std::optional<JS::NativeOptionalObjectTurboModule::ConstantsE::Builder> E;
NSString *F;
};
Expand Down Expand Up @@ -1780,7 +1780,7 @@ namespace JS {
struct Builder {
struct Input {
std::optional<bool> D;
id<NSObject> _Nullable A;
id<NSObject> _Nullable A;
std::optional<JS::NativeOptionalObjectTurboModule::ConstantsE::Builder> E;
NSString *F;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright (c) Meta Platforms, Inc. and 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
* @oncall react_native
*/

function wrapOptional(type: string, isRequired: boolean): string {
return isRequired ? type : `std::optional<${type}>`;
}

module.exports = {
wrapOptional,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (c) Meta Platforms, Inc. and 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
* @oncall react_native
*/

const objectTypeForPrimitiveType = {
boolean: 'Boolean',
double: 'Double',
float: 'Float',
int: 'Integer',
};

function wrapOptional(type: string, isRequired: boolean): string {
return isRequired
? type
: `@Nullable ${objectTypeForPrimitiveType[type] ?? type}`;
}

module.exports = {
wrapOptional,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright (c) Meta Platforms, Inc. and 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
* @oncall react_native
*/

function wrapOptional(type: string, isRequired: boolean): string {
return isRequired ? type : `${type} _Nullable`;
}

module.exports = {
wrapOptional,
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import type {
import type {AliasResolver} from './Utils';

const {unwrapNullable} = require('../../parsers/parsers-commons');
const {wrapOptional} = require('../TypeUtils/Cxx');
const {getEnumName, toSafeCppString} = require('../Utils');
const {indent} = require('../Utils');
const {
Expand Down Expand Up @@ -139,76 +140,71 @@ function translatePrimitiveJSTypeToCpp(
const [typeAnnotation, nullable] = unwrapNullable<NativeModuleTypeAnnotation>(
nullableTypeAnnotation,
);
const isRequired = !optional && !nullable;
const isRecursiveType = isDirectRecursiveMember(
parentObjectAliasName,
nullableTypeAnnotation,
);

const isRequired = (!optional && !nullable) || isRecursiveType;
let realTypeAnnotation = typeAnnotation;
if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
realTypeAnnotation = resolveAlias(realTypeAnnotation.name);
}

function wrap(type: string) {
return isRequired || isRecursiveType ? type : `std::optional<${type}>`;
}

switch (realTypeAnnotation.type) {
case 'ReservedTypeAnnotation':
switch (realTypeAnnotation.name) {
case 'RootTag':
return wrap('double');
return wrapOptional('double', isRequired);
default:
(realTypeAnnotation.name: empty);
throw new Error(createErrorMessage(realTypeAnnotation.name));
}
case 'VoidTypeAnnotation':
return 'void';
case 'StringTypeAnnotation':
return wrap('jsi::String');
return wrapOptional('jsi::String', isRequired);
case 'NumberTypeAnnotation':
return wrap('double');
return wrapOptional('double', isRequired);
case 'DoubleTypeAnnotation':
return wrap('double');
return wrapOptional('double', isRequired);
case 'FloatTypeAnnotation':
return wrap('double');
return wrapOptional('double', isRequired);
case 'Int32TypeAnnotation':
return wrap('int');
return wrapOptional('int', isRequired);
case 'BooleanTypeAnnotation':
return wrap('bool');
return wrapOptional('bool', isRequired);
case 'EnumDeclaration':
switch (realTypeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrap('jsi::Value');
return wrapOptional('jsi::Value', isRequired);
case 'StringTypeAnnotation':
return wrap('jsi::String');
return wrapOptional('jsi::String', isRequired);
default:
throw new Error(createErrorMessage(realTypeAnnotation.type));
}
case 'GenericObjectTypeAnnotation':
return wrap('jsi::Object');
return wrapOptional('jsi::Object', isRequired);
case 'UnionTypeAnnotation':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrap('double');
return wrapOptional('double', isRequired);
case 'ObjectTypeAnnotation':
return wrap('jsi::Object');
return wrapOptional('jsi::Object', isRequired);
case 'StringTypeAnnotation':
return wrap('jsi::String');
return wrapOptional('jsi::String', isRequired);
default:
throw new Error(createErrorMessage(realTypeAnnotation.type));
}
case 'ObjectTypeAnnotation':
return wrap('jsi::Object');
return wrapOptional('jsi::Object', isRequired);
case 'ArrayTypeAnnotation':
return wrap('jsi::Array');
return wrapOptional('jsi::Array', isRequired);
case 'FunctionTypeAnnotation':
return wrap('jsi::Function');
return wrapOptional('jsi::Function', isRequired);
case 'PromiseTypeAnnotation':
return wrap('jsi::Value');
return wrapOptional('jsi::Value', isRequired);
case 'MixedTypeAnnotation':
return wrap('jsi::Value');
return wrapOptional('jsi::Value', isRequired);
default:
(realTypeAnnotation.type: empty);
throw new Error(createErrorMessage(realTypeAnnotation.type));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
import type {AliasResolver} from './Utils';

const {unwrapNullable} = require('../../parsers/parsers-commons');
const {wrapOptional} = require('../TypeUtils/Java');
const {createAliasResolver, getModules} = require('./Utils');

type FilesOutput = Map<string, string>;
Expand Down Expand Up @@ -111,13 +112,8 @@ function translateFunctionParamToJavaType(
const [typeAnnotation, nullable] =
unwrapNullable<NativeModuleParamTypeAnnotation>(nullableTypeAnnotation);
const isRequired = !optional && !nullable;

function wrapNullable(javaType: string, nullableType?: string) {
if (!isRequired) {
imports.add('javax.annotation.Nullable');
return `@Nullable ${nullableType ?? javaType}`;
}
return javaType;
if (!isRequired) {
imports.add('javax.annotation.Nullable');
}

// FIXME: support class alias for args
Expand All @@ -130,59 +126,59 @@ function translateFunctionParamToJavaType(
case 'ReservedTypeAnnotation':
switch (realTypeAnnotation.name) {
case 'RootTag':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
default:
(realTypeAnnotation.name: empty);
throw new Error(createErrorMessage(realTypeAnnotation.name));
}
case 'StringTypeAnnotation':
return wrapNullable('String');
return wrapOptional('String', isRequired);
case 'NumberTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'FloatTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'DoubleTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'Int32TypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'BooleanTypeAnnotation':
return wrapNullable('boolean', 'Boolean');
return wrapOptional('boolean', isRequired);
case 'EnumDeclaration':
switch (realTypeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'StringTypeAnnotation':
return wrapNullable('String');
return wrapOptional('String', isRequired);
default:
throw new Error(createErrorMessage(realTypeAnnotation.type));
}
case 'UnionTypeAnnotation':
switch (typeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'ObjectTypeAnnotation':
imports.add('com.facebook.react.bridge.ReadableMap');
return wrapNullable('ReadableMap');
return wrapOptional('ReadableMap', isRequired);
case 'StringTypeAnnotation':
return wrapNullable('String');
return wrapOptional('String', isRequired);
default:
throw new Error(
`Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`,
);
}
case 'ObjectTypeAnnotation':
imports.add('com.facebook.react.bridge.ReadableMap');
return wrapNullable('ReadableMap');
return wrapOptional('ReadableMap', isRequired);
case 'GenericObjectTypeAnnotation':
// Treat this the same as ObjectTypeAnnotation for now.
imports.add('com.facebook.react.bridge.ReadableMap');
return wrapNullable('ReadableMap');
return wrapOptional('ReadableMap', isRequired);
case 'ArrayTypeAnnotation':
imports.add('com.facebook.react.bridge.ReadableArray');
return wrapNullable('ReadableArray');
return wrapOptional('ReadableArray', isRequired);
case 'FunctionTypeAnnotation':
imports.add('com.facebook.react.bridge.Callback');
return wrapNullable('Callback');
return wrapOptional('Callback', isRequired);
default:
(realTypeAnnotation.type: 'MixedTypeAnnotation');
throw new Error(createErrorMessage(realTypeAnnotation.type));
Expand All @@ -200,14 +196,12 @@ function translateFunctionReturnTypeToJavaType(
nullableReturnTypeAnnotation,
);

function wrapNullable(javaType: string, nullableType?: string) {
if (nullable) {
imports.add('javax.annotation.Nullable');
return `@Nullable ${nullableType ?? javaType}`;
}
return javaType;
if (nullable) {
imports.add('javax.annotation.Nullable');
}

const isRequired = !nullable;

// FIXME: support class alias for args
let realTypeAnnotation = returnTypeAnnotation;
if (realTypeAnnotation.type === 'TypeAliasTypeAnnotation') {
Expand All @@ -218,7 +212,7 @@ function translateFunctionReturnTypeToJavaType(
case 'ReservedTypeAnnotation':
switch (realTypeAnnotation.name) {
case 'RootTag':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
default:
(realTypeAnnotation.name: empty);
throw new Error(createErrorMessage(realTypeAnnotation.name));
Expand All @@ -228,49 +222,49 @@ function translateFunctionReturnTypeToJavaType(
case 'PromiseTypeAnnotation':
return 'void';
case 'StringTypeAnnotation':
return wrapNullable('String');
return wrapOptional('String', isRequired);
case 'NumberTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'FloatTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'DoubleTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'Int32TypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'BooleanTypeAnnotation':
return wrapNullable('boolean', 'Boolean');
return wrapOptional('boolean', isRequired);
case 'EnumDeclaration':
switch (realTypeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'StringTypeAnnotation':
return wrapNullable('String');
return wrapOptional('String', isRequired);
default:
throw new Error(createErrorMessage(realTypeAnnotation.type));
}
case 'UnionTypeAnnotation':
switch (realTypeAnnotation.memberType) {
case 'NumberTypeAnnotation':
return wrapNullable('double', 'Double');
return wrapOptional('double', isRequired);
case 'ObjectTypeAnnotation':
imports.add('com.facebook.react.bridge.WritableMap');
return wrapNullable('WritableMap');
return wrapOptional('WritableMap', isRequired);
case 'StringTypeAnnotation':
return wrapNullable('String');
return wrapOptional('String', isRequired);
default:
throw new Error(
`Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`,
);
}
case 'ObjectTypeAnnotation':
imports.add('com.facebook.react.bridge.WritableMap');
return wrapNullable('WritableMap');
return wrapOptional('WritableMap', isRequired);
case 'GenericObjectTypeAnnotation':
imports.add('com.facebook.react.bridge.WritableMap');
return wrapNullable('WritableMap');
return wrapOptional('WritableMap', isRequired);
case 'ArrayTypeAnnotation':
imports.add('com.facebook.react.bridge.WritableArray');
return wrapNullable('WritableArray');
return wrapOptional('WritableArray', isRequired);
default:
(realTypeAnnotation.type: 'MixedTypeAnnotation');
throw new Error(createErrorMessage(realTypeAnnotation.type));
Expand Down
Loading

0 comments on commit 7497df7

Please sign in to comment.