Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promise annotations must specify their elementType #46727

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/react-native-codegen/src/CodegenSchema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ export interface NativeModuleTypeAliasTypeAnnotation {

export interface NativeModulePromiseTypeAnnotation {
readonly type: 'PromiseTypeAnnotation';
readonly elementType?: Nullable<NativeModuleBaseTypeAnnotation> | undefined;
readonly elementType: Nullable<NativeModuleBaseTypeAnnotation> | VoidTypeAnnotation;
}

export type UnionTypeAnnotationMemberType =
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native-codegen/src/CodegenSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ export type NativeModuleTypeAliasTypeAnnotation = $ReadOnly<{

export type NativeModulePromiseTypeAnnotation = $ReadOnly<{
type: 'PromiseTypeAnnotation',
elementType?: Nullable<NativeModuleBaseTypeAnnotation>,
elementType: VoidTypeAnnotation | Nullable<NativeModuleBaseTypeAnnotation>,
}>;

export type UnionTypeAnnotationMemberType =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ const SCHEMA_WITH_TM_AND_FC: SchemaType = {
type: 'FunctionTypeAnnotation',
returnTypeAnnotation: {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
},
params: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,9 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
type: 'FunctionTypeAnnotation',
returnTypeAnnotation: {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
},
params: [
{
Expand All @@ -472,6 +475,9 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
type: 'FunctionTypeAnnotation',
returnTypeAnnotation: {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
},
params: [
{
Expand Down Expand Up @@ -1365,6 +1371,9 @@ const REAL_MODULE_EXAMPLE: SchemaType = {
type: 'FunctionTypeAnnotation',
returnTypeAnnotation: {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
},
params: [
{
Expand All @@ -1385,6 +1394,9 @@ const REAL_MODULE_EXAMPLE: SchemaType = {
type: 'FunctionTypeAnnotation',
returnTypeAnnotation: {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
},
params: [
{
Expand All @@ -1411,6 +1423,9 @@ const REAL_MODULE_EXAMPLE: SchemaType = {
type: 'FunctionTypeAnnotation',
returnTypeAnnotation: {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
},
params: [
{
Expand Down
10 changes: 10 additions & 0 deletions packages/react-native-codegen/src/parsers/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ class UnsupportedObjectPropertyTypeAnnotationParserError extends ParserError {
}
}

class UnsupportedObjectPropertyWithIndexerTypeAnnotationParserError extends ParserError {
constructor(nativeModuleName: string, propertyAST: $FlowFixMe) {
let message =
"'ObjectTypeAnnotation' cannot contain both an indexer and properties.";

super(nativeModuleName, propertyAST, message);
}
}

class UnsupportedObjectPropertyValueTypeAnnotationParserError extends ParserError {
constructor(
nativeModuleName: string,
Expand Down Expand Up @@ -455,6 +464,7 @@ module.exports = {
UnsupportedModuleEventEmitterPropertyParserError,
UnsupportedModulePropertyParserError,
UnsupportedObjectPropertyTypeAnnotationParserError,
UnsupportedObjectPropertyWithIndexerTypeAnnotationParserError,
UnsupportedObjectPropertyValueTypeAnnotationParserError,
UnsupportedObjectDirectRecursivePropertyParserError,
UnusedModuleInterfaceParserError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,34 @@ export interface Spec extends TurboModule {
export default TurboModuleRegistry.getEnforcing<Spec>('MixedValuesEnumNativeModule');
`;

const MAP_WITH_EXTRA_KEYS_NATIVE_MODULE = `
/**
* 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-local
* @format
*/

'use strict';

import type {TurboModule} from '../RCTExport';
import * as TurboModuleRegistry from '../TurboModuleRegistry';

type MapWithKey = {
[a: string]: ?string,
extra: string,
}

export interface Spec extends TurboModule {
+getMap: (a: MapWithKey) => string;
}

export default TurboModuleRegistry.getEnforcing<Spec>('MixedValuesEnumNativeModule');
`;

module.exports = {
NATIVE_MODULES_WITH_READ_ONLY_OBJECT_NO_TYPE_FOR_CONTENT,
NATIVE_MODULES_WITH_UNNAMED_PARAMS,
Expand All @@ -276,4 +304,5 @@ module.exports = {
TWO_NATIVE_EXTENDING_TURBO_MODULE,
EMPTY_ENUM_NATIVE_MODULE,
MIXED_VALUES_ENUM_NATIVE_MODULE,
MAP_WITH_EXTRA_KEYS_NATIVE_MODULE,
};
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export type ObjectAlias = {|
label: string,
truthy: boolean,
|};
export type PureObjectAlias = ObjectAlias;
export type ReadOnlyAlias = $ReadOnly<ObjectAlias>;

export interface Spec extends TurboModule {
Expand All @@ -171,6 +172,7 @@ export interface Spec extends TurboModule {
+getArray: (a: Array<A>) => {| a: B |};
+getStringFromAlias: (a: ObjectAlias) => string;
+getStringFromNullableAlias: (a: ?ObjectAlias) => string;
+getStringFromPureAlias: (a: PureObjectAlias) => string;
+getStringFromReadOnlyAlias: (a: ReadOnlyAlias) => string;
+getStringFromNullableReadOnlyAlias: (a: ?ReadOnlyAlias) => string;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

exports[`RN Codegen Flow Parser Fails with error message EMPTY_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enums should have at least one member and member values can not be mixed- they all must be either blank, number, or string values."`;

exports[`RN Codegen Flow Parser Fails with error message MAP_WITH_EXTRA_KEYS_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: 'ObjectTypeAnnotation' cannot contain both an indexer and properties."`;

exports[`RN Codegen Flow Parser Fails with error message MIXED_VALUES_ENUM_NATIVE_MODULE 1`] = `
"Syntax error in path/NativeSampleTurboModule.js: cannot use string initializer in number enum (19:2)
STR = 'str',
Expand Down Expand Up @@ -688,6 +690,26 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES
]
}
},
{
'name': 'getStringFromPureAlias',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'StringTypeAnnotation'
},
'params': [
{
'name': 'a',
'optional': false,
'typeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'ObjectAlias'
}
}
]
}
},
{
'name': 'getStringFromReadOnlyAlias',
'optional': false,
Expand Down Expand Up @@ -2384,7 +2406,10 @@ exports[`RN Codegen Flow Parser can generate fixture PROMISE_WITH_COMMONLY_USED_
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'PromiseTypeAnnotation'
'type': 'PromiseTypeAnnotation',
'elementType': {
'type': 'VoidTypeAnnotation'
}
},
'params': []
}
Expand All @@ -2395,7 +2420,10 @@ exports[`RN Codegen Flow Parser can generate fixture PROMISE_WITH_COMMONLY_USED_
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'PromiseTypeAnnotation'
'type': 'PromiseTypeAnnotation',
'elementType': {
'type': 'VoidTypeAnnotation'
}
},
'params': []
}
Expand All @@ -2406,7 +2434,10 @@ exports[`RN Codegen Flow Parser can generate fixture PROMISE_WITH_COMMONLY_USED_
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'PromiseTypeAnnotation'
'type': 'PromiseTypeAnnotation',
'elementType': {
'type': 'VoidTypeAnnotation'
}
},
'params': []
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {ParserErrorCapturer, TypeDeclarationMap} from '../../utils';
const {
UnsupportedEnumDeclarationParserError,
UnsupportedGenericParserError,
UnsupportedObjectPropertyWithIndexerTypeAnnotationParserError,
UnsupportedTypeAnnotationParserError,
} = require('../../errors');
const {
Expand Down Expand Up @@ -162,6 +163,14 @@ function translateTypeAnnotation(
const indexers = typeAnnotation.indexers.filter(
member => member.type === 'ObjectTypeIndexer',
);

if (indexers.length > 0 && typeAnnotation.properties.length > 0) {
throw new UnsupportedObjectPropertyWithIndexerTypeAnnotationParserError(
hasteModuleName,
typeAnnotation,
);
}

if (indexers.length > 0) {
// check the property type to prevent developers from using unsupported types
// the return value from `translateTypeAnnotation` is unused
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@ function emitPromise(
) {
return wrapNullable(nullable, {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
});
} else {
try {
Expand All @@ -335,6 +338,9 @@ function emitPromise(
} catch {
return wrapNullable(nullable, {
type: 'PromiseTypeAnnotation',
elementType: {
type: 'VoidTypeAnnotation',
},
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,31 @@ export default TurboModuleRegistry.getEnforcing<Spec>(
);
`;

const MAP_WITH_EXTRA_KEYS_NATIVE_MODULE = `
/**
* 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';

type MapWithKey = {
[a: string]: string | null,
extra: string,
}

export interface Spec extends TurboModule {
readonly getMap: (a: MapWithKey) => string;
}

export default TurboModuleRegistry.getEnforcing<Spec>('MapWithExtraKeysNativeModule');
`;

module.exports = {
NATIVE_MODULES_WITH_UNNAMED_PARAMS,
NATIVE_MODULES_WITH_PROMISE_WITHOUT_TYPE,
Expand All @@ -218,4 +243,5 @@ module.exports = {
TWO_NATIVE_EXTENDING_TURBO_MODULE,
EMPTY_ENUM_NATIVE_MODULE,
MIXED_VALUES_ENUM_NATIVE_MODULE,
MAP_WITH_EXTRA_KEYS_NATIVE_MODULE,
};
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export type ObjectAlias = {
label: string;
truthy: boolean;
};
export type PureObjectAlias = ObjectAlias;
export type ReadOnlyAlias = Readonly<ObjectAlias>;

export interface Spec extends TurboModule {
Expand All @@ -155,6 +156,7 @@ export interface Spec extends TurboModule {
readonly getArray: (a: Array<A>) => {a: B};
readonly getStringFromAlias: (a: ObjectAlias) => string;
readonly getStringFromNullableAlias: (a: ObjectAlias | null) => string;
readonly getStringFromPureAlias: (a: PureObjectAlias) => string;
readonly getStringFromReadOnlyAlias: (a: ReadOnlyAlias) => string;
readonly getStringFromNullableReadOnlyAlias: (a: ReadOnlyAlias | null) => string;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

exports[`RN Codegen TypeScript Parser Fails with error message EMPTY_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enums should have at least one member."`;

exports[`RN Codegen TypeScript Parser Fails with error message MAP_WITH_EXTRA_KEYS_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: 'ObjectTypeAnnotation' cannot contain both an indexer and properties."`;

exports[`RN Codegen TypeScript Parser Fails with error message MIXED_VALUES_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enum values can not be mixed. They all must be either blank, number, or string values."`;

exports[`RN Codegen TypeScript Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT 1`] = `"Module NativeSampleTurboModule: Generic 'Array' must have type parameters."`;
Expand Down Expand Up @@ -679,6 +681,26 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AL
]
}
},
{
'name': 'getStringFromPureAlias',
'optional': false,
'typeAnnotation': {
'type': 'FunctionTypeAnnotation',
'returnTypeAnnotation': {
'type': 'StringTypeAnnotation'
},
'params': [
{
'name': 'a',
'optional': false,
'typeAnnotation': {
'type': 'TypeAliasTypeAnnotation',
'name': 'ObjectAlias'
}
}
]
}
},
{
'name': 'getStringFromReadOnlyAlias',
'optional': false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type {
const {
UnsupportedEnumDeclarationParserError,
UnsupportedGenericParserError,
UnsupportedObjectPropertyWithIndexerTypeAnnotationParserError,
UnsupportedTypeAnnotationParserError,
} = require('../../errors');
const {parseObjectProperty} = require('../../parsers-commons');
Expand Down Expand Up @@ -308,6 +309,18 @@ function translateTypeAnnotation(
const indexSignatures = typeAnnotation.members.filter(
member => member.type === 'TSIndexSignature',
);

const properties = typeAnnotation.members.filter(
member => member.type === 'TSPropertySignature',
);

if (indexSignatures.length > 0 && properties.length > 0) {
throw new UnsupportedObjectPropertyWithIndexerTypeAnnotationParserError(
hasteModuleName,
typeAnnotation,
);
}

if (indexSignatures.length > 0) {
// check the property type to prevent developers from using unsupported types
// the return value from `translateTypeAnnotation` is unused
Expand Down
Loading