Support TypeScript array types for turbo module (module only) (#34183)
Summary: Turbo module codegen supports arrays in both Flow and TypeScript, but it only recognize `Array<T>` and `ReadonlyArray<T>` in TypeScript. In this change, `T[]` and `readonly T[]` are made recognizable in codegen. ## Changelog [General] [Added] - Support TypeScript array types for turbo module (module only) Pull Request resolved: https://github.com/facebook/react-native/pull/34183 Test Plan: `yarn jest` passed in `packages/react-native-codegen` Reviewed By: lunaleaps Differential Revision: D37812638 Pulled By: cipolleschi fbshipit-source-id: d63b0585497a43c274d50e1877baab5d1cc3f8fa
This commit is contained in:
Родитель
89f090016d
Коммит
f0c4c291e1
|
@ -322,6 +322,27 @@ export interface Spec extends TurboModule {
|
|||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_BASIC_ARRAY2 = `
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly getArray: (arg: string[]) => string[];
|
||||
readonly getArray: (arg: readonly string[]) => readonly string[];
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_OBJECT_WITH_OBJECT_DEFINED_IN_FILE_AS_PROPERTY = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
@ -377,6 +398,28 @@ export interface Spec extends TurboModule {
|
|||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_ARRAY2_WITH_UNION_AND_TOUPLE = `
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly getArray: (
|
||||
arg: [string, string][],
|
||||
) => (string | number | boolean)[];
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_ARRAY_WITH_ALIAS = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
@ -399,6 +442,28 @@ export interface Spec extends TurboModule {
|
|||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_ARRAY2_WITH_ALIAS = `
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export type SomeString = string;
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly getArray: (arg: SomeString[]) => string[];
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_COMPLEX_ARRAY = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
@ -421,6 +486,28 @@ export interface Spec extends TurboModule {
|
|||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_COMPLEX_ARRAY2 = `
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly getArray: (
|
||||
arg: string[][][][][],
|
||||
) => string[][][];
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_PROMISE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
@ -534,6 +621,7 @@ export default TurboModuleRegistry.getEnforcing<Spec>(
|
|||
module.exports = {
|
||||
NATIVE_MODULE_WITH_OBJECT_WITH_OBJECT_DEFINED_IN_FILE_AS_PROPERTY,
|
||||
NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE,
|
||||
NATIVE_MODULE_WITH_ARRAY2_WITH_UNION_AND_TOUPLE,
|
||||
NATIVE_MODULE_WITH_FLOAT_AND_INT32,
|
||||
NATIVE_MODULE_WITH_ALIASES,
|
||||
NATIVE_MODULE_WITH_NESTED_ALIASES,
|
||||
|
@ -545,8 +633,11 @@ module.exports = {
|
|||
NATIVE_MODULE_WITH_ROOT_TAG,
|
||||
NATIVE_MODULE_WITH_NULLABLE_PARAM,
|
||||
NATIVE_MODULE_WITH_BASIC_ARRAY,
|
||||
NATIVE_MODULE_WITH_BASIC_ARRAY2,
|
||||
NATIVE_MODULE_WITH_COMPLEX_ARRAY,
|
||||
NATIVE_MODULE_WITH_COMPLEX_ARRAY2,
|
||||
NATIVE_MODULE_WITH_ARRAY_WITH_ALIAS,
|
||||
NATIVE_MODULE_WITH_ARRAY2_WITH_ALIAS,
|
||||
NATIVE_MODULE_WITH_BASIC_PARAM_TYPES,
|
||||
NATIVE_MODULE_WITH_CALLBACK,
|
||||
EMPTY_NATIVE_MODULE,
|
||||
|
|
|
@ -369,6 +369,49 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_ARRAY2_WITH_ALIAS 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliases': {},
|
||||
'spec': {
|
||||
'properties': [
|
||||
{
|
||||
'name': 'getArray',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'FunctionTypeAnnotation',
|
||||
'returnTypeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
},
|
||||
'params': [
|
||||
{
|
||||
'name': 'arg',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
'moduleNames': [
|
||||
'SampleTurboModule'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
@ -406,6 +449,43 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_ARRAY2_WITH_UNION_AND_TOUPLE 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliases': {},
|
||||
'spec': {
|
||||
'properties': [
|
||||
{
|
||||
'name': 'getArray',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'FunctionTypeAnnotation',
|
||||
'returnTypeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation'
|
||||
},
|
||||
'params': [
|
||||
{
|
||||
'name': 'arg',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
'moduleNames': [
|
||||
'SampleTurboModule'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BASIC_ARRAY 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
@ -474,6 +554,74 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BA
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BASIC_ARRAY2 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliases': {},
|
||||
'spec': {
|
||||
'properties': [
|
||||
{
|
||||
'name': 'getArray',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'FunctionTypeAnnotation',
|
||||
'returnTypeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
},
|
||||
'params': [
|
||||
{
|
||||
'name': 'arg',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'getArray',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'FunctionTypeAnnotation',
|
||||
'returnTypeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
},
|
||||
'params': [
|
||||
{
|
||||
'name': 'arg',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
'moduleNames': [
|
||||
'SampleTurboModule'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PARAM_TYPES 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
@ -691,6 +839,67 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_CO
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ARRAY2 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliases': {},
|
||||
'spec': {
|
||||
'properties': [
|
||||
{
|
||||
'name': 'getArray',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'FunctionTypeAnnotation',
|
||||
'returnTypeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'params': [
|
||||
{
|
||||
'name': 'arg',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
'moduleNames': [
|
||||
'SampleTurboModule'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_OBJECTS 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
|
|
@ -61,6 +61,82 @@ function nullGuard<T>(fn: () => T): ?T {
|
|||
return fn();
|
||||
}
|
||||
|
||||
function translateArrayTypeAnnotation(
|
||||
hasteModuleName: string,
|
||||
types: TypeDeclarationMap,
|
||||
aliasMap: {...NativeModuleAliasMap},
|
||||
cxxOnly: boolean,
|
||||
tsArrayType: 'Array' | 'ReadonlyArray',
|
||||
tsElementType: $FlowFixMe,
|
||||
nullable: $FlowFixMe,
|
||||
): Nullable<NativeModuleTypeAnnotation> {
|
||||
try {
|
||||
/**
|
||||
* TODO(T72031674): Migrate all our NativeModule specs to not use
|
||||
* invalid Array ElementTypes. Then, make the elementType a required
|
||||
* parameter.
|
||||
*/
|
||||
const [elementType, isElementTypeNullable] = unwrapNullable(
|
||||
translateTypeAnnotation(
|
||||
hasteModuleName,
|
||||
tsElementType,
|
||||
types,
|
||||
aliasMap,
|
||||
/**
|
||||
* TODO(T72031674): Ensure that all ParsingErrors that are thrown
|
||||
* while parsing the array element don't get captured and collected.
|
||||
* Why? If we detect any parsing error while parsing the element,
|
||||
* we should default it to null down the line, here. This is
|
||||
* the correct behaviour until we migrate all our NativeModule specs
|
||||
* to be parseable.
|
||||
*/
|
||||
nullGuard,
|
||||
cxxOnly,
|
||||
),
|
||||
);
|
||||
|
||||
if (elementType.type === 'VoidTypeAnnotation') {
|
||||
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
||||
hasteModuleName,
|
||||
tsElementType,
|
||||
tsArrayType,
|
||||
'void',
|
||||
);
|
||||
}
|
||||
|
||||
if (elementType.type === 'PromiseTypeAnnotation') {
|
||||
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
||||
hasteModuleName,
|
||||
tsElementType,
|
||||
tsArrayType,
|
||||
'Promise',
|
||||
);
|
||||
}
|
||||
|
||||
if (elementType.type === 'FunctionTypeAnnotation') {
|
||||
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
||||
hasteModuleName,
|
||||
tsElementType,
|
||||
tsArrayType,
|
||||
'FunctionTypeAnnotation',
|
||||
);
|
||||
}
|
||||
|
||||
const finalTypeAnnotation: NativeModuleArrayTypeAnnotation<
|
||||
Nullable<NativeModuleBaseTypeAnnotation>,
|
||||
> = {
|
||||
type: 'ArrayTypeAnnotation',
|
||||
elementType: wrapNullable(isElementTypeNullable, elementType),
|
||||
};
|
||||
|
||||
return wrapNullable(nullable, finalTypeAnnotation);
|
||||
} catch (ex) {
|
||||
return wrapNullable(nullable, {
|
||||
type: 'ArrayTypeAnnotation',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function translateTypeAnnotation(
|
||||
hasteModuleName: string,
|
||||
/**
|
||||
|
@ -76,6 +152,38 @@ function translateTypeAnnotation(
|
|||
resolveTypeAnnotation(typeScriptTypeAnnotation, types);
|
||||
|
||||
switch (typeAnnotation.type) {
|
||||
case 'TSArrayType': {
|
||||
return translateArrayTypeAnnotation(
|
||||
hasteModuleName,
|
||||
types,
|
||||
aliasMap,
|
||||
cxxOnly,
|
||||
'Array',
|
||||
typeAnnotation.elementType,
|
||||
nullable,
|
||||
);
|
||||
}
|
||||
case 'TSTypeOperator': {
|
||||
if (
|
||||
typeAnnotation.operator === 'readonly' &&
|
||||
typeAnnotation.typeAnnotation.type === 'TSArrayType'
|
||||
) {
|
||||
return translateArrayTypeAnnotation(
|
||||
hasteModuleName,
|
||||
types,
|
||||
aliasMap,
|
||||
cxxOnly,
|
||||
'ReadonlyArray',
|
||||
typeAnnotation.typeAnnotation.elementType,
|
||||
nullable,
|
||||
);
|
||||
} else {
|
||||
throw new UnsupportedTypeScriptGenericParserError(
|
||||
hasteModuleName,
|
||||
typeAnnotation,
|
||||
);
|
||||
}
|
||||
}
|
||||
case 'TSTypeReference': {
|
||||
switch (typeAnnotation.typeName.name) {
|
||||
case 'RootTag': {
|
||||
|
@ -101,71 +209,15 @@ function translateTypeAnnotation(
|
|||
typeAnnotation,
|
||||
);
|
||||
|
||||
try {
|
||||
/**
|
||||
* TODO(T72031674): Migrate all our NativeModule specs to not use
|
||||
* invalid Array ElementTypes. Then, make the elementType a required
|
||||
* parameter.
|
||||
*/
|
||||
const [elementType, isElementTypeNullable] = unwrapNullable(
|
||||
translateTypeAnnotation(
|
||||
hasteModuleName,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
types,
|
||||
aliasMap,
|
||||
/**
|
||||
* TODO(T72031674): Ensure that all ParsingErrors that are thrown
|
||||
* while parsing the array element don't get captured and collected.
|
||||
* Why? If we detect any parsing error while parsing the element,
|
||||
* we should default it to null down the line, here. This is
|
||||
* the correct behaviour until we migrate all our NativeModule specs
|
||||
* to be parseable.
|
||||
*/
|
||||
nullGuard,
|
||||
cxxOnly,
|
||||
),
|
||||
);
|
||||
|
||||
if (elementType.type === 'VoidTypeAnnotation') {
|
||||
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
||||
hasteModuleName,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
typeAnnotation.type,
|
||||
'void',
|
||||
);
|
||||
}
|
||||
|
||||
if (elementType.type === 'PromiseTypeAnnotation') {
|
||||
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
||||
hasteModuleName,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
typeAnnotation.type,
|
||||
'Promise',
|
||||
);
|
||||
}
|
||||
|
||||
if (elementType.type === 'FunctionTypeAnnotation') {
|
||||
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
||||
hasteModuleName,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
typeAnnotation.type,
|
||||
'FunctionTypeAnnotation',
|
||||
);
|
||||
}
|
||||
|
||||
const finalTypeAnnotation: NativeModuleArrayTypeAnnotation<
|
||||
Nullable<NativeModuleBaseTypeAnnotation>,
|
||||
> = {
|
||||
type: 'ArrayTypeAnnotation',
|
||||
elementType: wrapNullable(isElementTypeNullable, elementType),
|
||||
};
|
||||
|
||||
return wrapNullable(nullable, finalTypeAnnotation);
|
||||
} catch (ex) {
|
||||
return wrapNullable(nullable, {
|
||||
type: 'ArrayTypeAnnotation',
|
||||
});
|
||||
}
|
||||
return translateArrayTypeAnnotation(
|
||||
hasteModuleName,
|
||||
types,
|
||||
aliasMap,
|
||||
cxxOnly,
|
||||
typeAnnotation.type,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
nullable,
|
||||
);
|
||||
}
|
||||
case 'Readonly': {
|
||||
assertGenericTypeAnnotationHasExactlyOneTypeParameter(
|
||||
|
|
Загрузка…
Ссылка в новой задаче