mirror of
https://github.com/react/react-native.git
synced 2026-09-28 05:13:06 +08:00
Align TurboModule EventEmitter payload types across platforms (#58063)
Summary: Pull Request resolved: https://github.com/react/react-native/pull/58063 Codegen's `EventEmitter<T>` support for TurboModules diverged between platforms in two ways: - The explicit number types `Double`, `Float` and `Int32` worked as emitter payloads on Android and C++, but iOS rejected them at codegen time (plain `number` worked). iOS now maps all of them to `NSNumber *_Nonnull`, matching how plain `number` is already emitted. - `ArrayBuffer` was rejected on Android and iOS, but the C++ generator silently accepted it and produced a `jsi::ArrayBuffer` emitter. `ArrayBuffer` is not emittable on any platform — Android emitters always carry a `folly::dynamic` payload, which cannot hold raw bytes — and the schema type `NativeModuleEventEmitterBaseTypeAnnotation` already excluded it. It is now rejected everywhere. `ArrayBuffer` payloads are rejected in the shared parser, so Flow and TypeScript specs produce the same error, and the three generators keep an equivalent guard so schemas that are constructed without going through the parser fail the same way. `ArrayBuffer` remains supported as a method argument and as a synchronous return value. Changelog: [iOS][Added] - Support `Double`, `Float` and `Int32` payloads for TurboModule `EventEmitter`s [General][Breaking] - Reject `ArrayBuffer` as a TurboModule `EventEmitter` payload on all platforms Reviewed By: GijsWeterings Differential Revision: D116952150 fbshipit-source-id: e148a394c4916b3ebfbd3f559b190a5910b29de1
This commit is contained in:
committed by
meta-codesync[bot]
parent
2c4278d83b
commit
ab2ea649e6
@@ -40,6 +40,7 @@ const {
|
||||
getModules,
|
||||
isArrayRecursiveMember,
|
||||
isDirectRecursiveMember,
|
||||
throwIfUnsupportedEventEmitterPayload,
|
||||
} = require('./Utils');
|
||||
|
||||
type FilesOutput = Map<string, string>;
|
||||
@@ -638,6 +639,11 @@ function translateEventEmitterToCpp(
|
||||
resolveAlias: AliasResolver,
|
||||
enumMap: NativeModuleEnumMap,
|
||||
): EventEmitterCpp {
|
||||
throwIfUnsupportedEventEmitterPayload(
|
||||
eventEmitter.name,
|
||||
eventEmitter.typeAnnotation.typeAnnotation,
|
||||
);
|
||||
|
||||
const isVoidTypeAnnotation =
|
||||
eventEmitter.typeAnnotation.typeAnnotation.type === 'VoidTypeAnnotation';
|
||||
const templateName = `${toPascalCase(eventEmitter.name)}Type`;
|
||||
|
||||
+5
-5
@@ -28,6 +28,7 @@ const {parseValidUnionType, toPascalCase} = require('../Utils');
|
||||
const {
|
||||
createAliasResolver,
|
||||
getModules,
|
||||
throwIfUnsupportedEventEmitterPayload,
|
||||
throwIfUnsupportedPromiseArrayBuffer,
|
||||
} = require('./Utils');
|
||||
|
||||
@@ -141,6 +142,9 @@ function translateEventEmitterTypeToJavaType(
|
||||
imports: Set<string>,
|
||||
): string {
|
||||
const typeAnnotation = eventEmitter.typeAnnotation.typeAnnotation;
|
||||
|
||||
throwIfUnsupportedEventEmitterPayload(eventEmitter.name, typeAnnotation);
|
||||
|
||||
switch (typeAnnotation.type) {
|
||||
case 'StringTypeAnnotation':
|
||||
return 'String';
|
||||
@@ -179,12 +183,8 @@ function translateEventEmitterTypeToJavaType(
|
||||
case 'ArrayTypeAnnotation':
|
||||
imports.add('com.facebook.react.bridge.ReadableArray');
|
||||
return 'ReadableArray';
|
||||
case 'DoubleTypeAnnotation':
|
||||
case 'FloatTypeAnnotation':
|
||||
case 'Int32TypeAnnotation':
|
||||
case 'VoidTypeAnnotation':
|
||||
case 'ArrayBufferTypeAnnotation':
|
||||
// TODO: Add support for these types
|
||||
// Void emitters take no argument, so the caller never asks for a type.
|
||||
throw new Error(
|
||||
`Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`,
|
||||
);
|
||||
|
||||
Vendored
+7
-4
@@ -11,12 +11,15 @@
|
||||
import type {NativeModuleEventEmitterShape} from '../../../CodegenSchema';
|
||||
|
||||
const {parseValidUnionType, toPascalCase} = require('../../Utils');
|
||||
const {throwIfUnsupportedEventEmitterPayload} = require('../Utils');
|
||||
|
||||
function getEventEmitterTypeObjCType(
|
||||
eventEmitter: NativeModuleEventEmitterShape,
|
||||
): string {
|
||||
const typeAnnotation = eventEmitter.typeAnnotation.typeAnnotation;
|
||||
|
||||
throwIfUnsupportedEventEmitterPayload(eventEmitter.name, typeAnnotation);
|
||||
|
||||
switch (typeAnnotation.type) {
|
||||
case 'StringTypeAnnotation':
|
||||
return 'NSString *_Nonnull';
|
||||
@@ -39,6 +42,9 @@ function getEventEmitterTypeObjCType(
|
||||
}
|
||||
case 'NumberTypeAnnotation':
|
||||
case 'NumberLiteralTypeAnnotation':
|
||||
case 'DoubleTypeAnnotation':
|
||||
case 'FloatTypeAnnotation':
|
||||
case 'Int32TypeAnnotation':
|
||||
return 'NSNumber *_Nonnull';
|
||||
case 'BooleanTypeAnnotation':
|
||||
case 'BooleanLiteralTypeAnnotation':
|
||||
@@ -49,11 +55,8 @@ function getEventEmitterTypeObjCType(
|
||||
return 'NSDictionary *';
|
||||
case 'ArrayTypeAnnotation':
|
||||
return 'NSArray<id<NSObject>> *';
|
||||
case 'DoubleTypeAnnotation':
|
||||
case 'FloatTypeAnnotation':
|
||||
case 'Int32TypeAnnotation':
|
||||
case 'VoidTypeAnnotation':
|
||||
// TODO: Add support for these types
|
||||
// Void emitters take no argument, so both callers skip this function.
|
||||
throw new Error(
|
||||
`Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`,
|
||||
);
|
||||
|
||||
@@ -118,10 +118,29 @@ function throwIfUnsupportedPromiseArrayBuffer(
|
||||
}
|
||||
}
|
||||
|
||||
// ArrayBuffer is not emittable on any platform: Android emitters always carry a
|
||||
// folly::dynamic payload, which cannot hold raw bytes, and neither the ObjC nor
|
||||
// the C++ emitter contract can hand out a buffer that outlives the emit call.
|
||||
// The parser rejects this too; the guard here also covers schemas built without
|
||||
// going through the parser.
|
||||
function throwIfUnsupportedEventEmitterPayload(
|
||||
eventEmitterName: string,
|
||||
typeAnnotation: NativeModuleTypeAnnotation,
|
||||
): void {
|
||||
if (typeAnnotation.type === 'ArrayBufferTypeAnnotation') {
|
||||
throw new Error(
|
||||
`Unsupported eventType for ${eventEmitterName}. Found: ${typeAnnotation.type}. ` +
|
||||
'ArrayBuffer is not supported as an EventEmitter payload on any platform. ' +
|
||||
'Pass the ArrayBuffer through a method instead.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createAliasResolver,
|
||||
getModules,
|
||||
isDirectRecursiveMember,
|
||||
isArrayRecursiveMember,
|
||||
throwIfUnsupportedEventEmitterPayload,
|
||||
throwIfUnsupportedPromiseArrayBuffer,
|
||||
};
|
||||
|
||||
+30
@@ -130,6 +130,36 @@ const EVENT_EMITTER_MODULES: SchemaType = {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'onEvent7',
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: {
|
||||
type: 'DoubleTypeAnnotation',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'onEvent8',
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: {
|
||||
type: 'FloatTypeAnnotation',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'onEvent9',
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: {
|
||||
type: 'Int32TypeAnnotation',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
methods: [
|
||||
{
|
||||
|
||||
+37
@@ -10,9 +10,37 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {SchemaType} from '../../../CodegenSchema';
|
||||
|
||||
const fixtures = require('../__test_fixtures__/fixtures.js');
|
||||
const generator = require('../GenerateModuleH.js');
|
||||
|
||||
const ARRAY_BUFFER_EVENT_EMITTER_SCHEMA: SchemaType = {
|
||||
modules: {
|
||||
NativeSampleTurboModule: {
|
||||
type: 'NativeModule',
|
||||
aliasMap: {},
|
||||
enumMap: {},
|
||||
spec: {
|
||||
eventEmitters: [
|
||||
{
|
||||
name: 'onBuffer',
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: {
|
||||
type: 'ArrayBufferTypeAnnotation',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
methods: [],
|
||||
},
|
||||
moduleName: 'SampleTurboModule',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('GenerateModuleH', () => {
|
||||
Object.keys(fixtures)
|
||||
.sort()
|
||||
@@ -29,4 +57,13 @@ describe('GenerateModuleH', () => {
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('throws for an EventEmitter with an ArrayBuffer payload', () => {
|
||||
expect(() =>
|
||||
generator.generate(
|
||||
'array_buffer_event_emitter_throws',
|
||||
ARRAY_BUFFER_EVENT_EMITTER_SCHEMA,
|
||||
),
|
||||
).toThrow(/ArrayBuffer is not supported as an EventEmitter payload/);
|
||||
});
|
||||
});
|
||||
|
||||
Vendored
+36
@@ -71,4 +71,40 @@ describe('GenerateModuleHObjCpp', () => {
|
||||
),
|
||||
).toThrow(/Promise<ArrayBuffer> is not supported/);
|
||||
});
|
||||
|
||||
it('throws for an EventEmitter with an ArrayBuffer payload', () => {
|
||||
const schema: SchemaType = {
|
||||
modules: {
|
||||
NativeSampleTurboModule: {
|
||||
type: 'NativeModule',
|
||||
aliasMap: {},
|
||||
enumMap: {},
|
||||
spec: {
|
||||
eventEmitters: [
|
||||
{
|
||||
name: 'onBuffer',
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: {
|
||||
type: 'ArrayBufferTypeAnnotation',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
methods: [],
|
||||
},
|
||||
moduleName: 'SampleTurboModule',
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(() =>
|
||||
generator.generate(
|
||||
'array_buffer_event_emitter_throws',
|
||||
schema,
|
||||
'com.facebook.fbreact.specs',
|
||||
false,
|
||||
),
|
||||
).toThrow(/ArrayBuffer is not supported as an EventEmitter payload/);
|
||||
});
|
||||
});
|
||||
|
||||
Vendored
+31
@@ -64,4 +64,35 @@ describe('GenerateModuleJavaSpec', () => {
|
||||
generator.generate('array_buffer_promise_throws', schema),
|
||||
).toThrow(/Promise<ArrayBuffer> is not supported/);
|
||||
});
|
||||
|
||||
it('throws for an EventEmitter with an ArrayBuffer payload', () => {
|
||||
const schema: SchemaType = {
|
||||
modules: {
|
||||
NativeSampleTurboModule: {
|
||||
type: 'NativeModule',
|
||||
aliasMap: {},
|
||||
enumMap: {},
|
||||
spec: {
|
||||
eventEmitters: [
|
||||
{
|
||||
name: 'onBuffer',
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: {
|
||||
type: 'ArrayBufferTypeAnnotation',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
methods: [],
|
||||
},
|
||||
moduleName: 'SampleTurboModule',
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(() =>
|
||||
generator.generate('array_buffer_event_emitter_throws', schema),
|
||||
).toThrow(/ArrayBuffer is not supported as an EventEmitter payload/);
|
||||
});
|
||||
});
|
||||
|
||||
+24
@@ -1083,6 +1083,9 @@ protected:
|
||||
eventEmitterMap_[\\"onEvent4\\"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
|
||||
eventEmitterMap_[\\"onEvent5\\"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
|
||||
eventEmitterMap_[\\"onEvent6\\"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
|
||||
eventEmitterMap_[\\"onEvent7\\"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
|
||||
eventEmitterMap_[\\"onEvent8\\"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
|
||||
eventEmitterMap_[\\"onEvent9\\"] = std::make_shared<AsyncEventEmitter<jsi::Value>>();
|
||||
}
|
||||
|
||||
void emitOnEvent1() {
|
||||
@@ -1123,6 +1126,27 @@ protected:
|
||||
return bridging::toJs(rt, eventValue, jsInvoker);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename OnEvent7Type> void emitOnEvent7(OnEvent7Type value) {
|
||||
static_assert(bridging::supportsFromJs<OnEvent7Type, double>, \\"value cannnot be converted to double\\");
|
||||
static_cast<AsyncEventEmitter<jsi::Value>&>(*eventEmitterMap_[\\"onEvent7\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
|
||||
return bridging::toJs(rt, eventValue, jsInvoker);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename OnEvent8Type> void emitOnEvent8(OnEvent8Type value) {
|
||||
static_assert(bridging::supportsFromJs<OnEvent8Type, double>, \\"value cannnot be converted to double\\");
|
||||
static_cast<AsyncEventEmitter<jsi::Value>&>(*eventEmitterMap_[\\"onEvent8\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
|
||||
return bridging::toJs(rt, eventValue, jsInvoker);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename OnEvent9Type> void emitOnEvent9(OnEvent9Type value) {
|
||||
static_assert(bridging::supportsFromJs<OnEvent9Type, int>, \\"value cannnot be converted to int\\");
|
||||
static_cast<AsyncEventEmitter<jsi::Value>&>(*eventEmitterMap_[\\"onEvent9\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value {
|
||||
return bridging::toJs(rt, eventValue, jsInvoker);
|
||||
});
|
||||
}
|
||||
private:
|
||||
static jsi::Value __voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* /*args*/, size_t /*count*/) {
|
||||
static_assert(
|
||||
|
||||
+3
@@ -614,6 +614,9 @@ facebook::react::EventEmitterCallback _eventEmitterCallback;
|
||||
- (void)emitOnEvent4:(BOOL)value;
|
||||
- (void)emitOnEvent5:(NSDictionary *)value;
|
||||
- (void)emitOnEvent6:(NSArray<id<NSObject>> *)value;
|
||||
- (void)emitOnEvent7:(NSNumber *_Nonnull)value;
|
||||
- (void)emitOnEvent8:(NSNumber *_Nonnull)value;
|
||||
- (void)emitOnEvent9:(NSNumber *_Nonnull)value;
|
||||
@end
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
+21
@@ -292,6 +292,27 @@ public abstract class NativeSampleTurboModuleSpec extends ReactContextBaseJavaMo
|
||||
}
|
||||
}
|
||||
|
||||
protected final void emitOnEvent7(double value) {
|
||||
CxxCallbackImpl eventEmitterCallback = mEventEmitterCallback;
|
||||
if (eventEmitterCallback != null) {
|
||||
eventEmitterCallback.invoke(\\"onEvent7\\", value);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void emitOnEvent8(double value) {
|
||||
CxxCallbackImpl eventEmitterCallback = mEventEmitterCallback;
|
||||
if (eventEmitterCallback != null) {
|
||||
eventEmitterCallback.invoke(\\"onEvent8\\", value);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void emitOnEvent9(double value) {
|
||||
CxxCallbackImpl eventEmitterCallback = mEventEmitterCallback;
|
||||
if (eventEmitterCallback != null) {
|
||||
eventEmitterCallback.invoke(\\"onEvent9\\", value);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
@DoNotStrip
|
||||
public abstract void voidFunc();
|
||||
|
||||
+3
@@ -280,6 +280,9 @@ NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboMo
|
||||
eventEmitterMap_[\\"onEvent4\\"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
|
||||
eventEmitterMap_[\\"onEvent5\\"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
|
||||
eventEmitterMap_[\\"onEvent6\\"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
|
||||
eventEmitterMap_[\\"onEvent7\\"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
|
||||
eventEmitterMap_[\\"onEvent8\\"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
|
||||
eventEmitterMap_[\\"onEvent9\\"] = std::make_shared<AsyncEventEmitter<folly::dynamic>>();
|
||||
configureEventEmitterCallback();
|
||||
}
|
||||
|
||||
|
||||
+24
@@ -366,6 +366,27 @@ Map {
|
||||
eventEmitterCallback(\\"onEvent6\\", value);
|
||||
}
|
||||
}
|
||||
- (void)emitOnEvent7:(NSNumber *_Nonnull)value
|
||||
{
|
||||
auto eventEmitterCallback = _eventEmitterCallback;
|
||||
if (eventEmitterCallback) {
|
||||
eventEmitterCallback(\\"onEvent7\\", value);
|
||||
}
|
||||
}
|
||||
- (void)emitOnEvent8:(NSNumber *_Nonnull)value
|
||||
{
|
||||
auto eventEmitterCallback = _eventEmitterCallback;
|
||||
if (eventEmitterCallback) {
|
||||
eventEmitterCallback(\\"onEvent8\\", value);
|
||||
}
|
||||
}
|
||||
- (void)emitOnEvent9:(NSNumber *_Nonnull)value
|
||||
{
|
||||
auto eventEmitterCallback = _eventEmitterCallback;
|
||||
if (eventEmitterCallback) {
|
||||
eventEmitterCallback(\\"onEvent9\\", value);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper
|
||||
{
|
||||
@@ -391,6 +412,9 @@ namespace facebook::react {
|
||||
eventEmitterMap_[\\"onEvent4\\"] = std::make_shared<AsyncEventEmitter<id>>();
|
||||
eventEmitterMap_[\\"onEvent5\\"] = std::make_shared<AsyncEventEmitter<id>>();
|
||||
eventEmitterMap_[\\"onEvent6\\"] = std::make_shared<AsyncEventEmitter<id>>();
|
||||
eventEmitterMap_[\\"onEvent7\\"] = std::make_shared<AsyncEventEmitter<id>>();
|
||||
eventEmitterMap_[\\"onEvent8\\"] = std::make_shared<AsyncEventEmitter<id>>();
|
||||
eventEmitterMap_[\\"onEvent9\\"] = std::make_shared<AsyncEventEmitter<id>>();
|
||||
setEventEmitterCallback([eventEmitterMap = eventEmitterMap_](const std::string &name, id value) {
|
||||
auto it = eventEmitterMap.find(name);
|
||||
if (it != eventEmitterMap.end() && it->second) {
|
||||
|
||||
@@ -18,6 +18,7 @@ const {
|
||||
throwIfArgumentPropsAreNull,
|
||||
throwIfArrayElementTypeAnnotationIsUnsupported,
|
||||
throwIfBubblingTypeIsNull,
|
||||
throwIfEventEmitterPayloadTypeIsUnsupported,
|
||||
throwIfEventHasNoName,
|
||||
throwIfIncorrectModuleRegistryCallArgument,
|
||||
throwIfIncorrectModuleRegistryCallTypeParameterParserError,
|
||||
@@ -825,6 +826,35 @@ describe('throwIfArrayElementTypeAnnotationIsUnsupported', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('throwIfEventEmitterPayloadTypeIsUnsupported', () => {
|
||||
const {
|
||||
UnsupportedModuleEventEmitterPayloadTypeParserError,
|
||||
} = require('../errors.js');
|
||||
const moduleName = 'moduleName';
|
||||
|
||||
it('throws the error if the payload is an ArrayBuffer', () => {
|
||||
expect(() => {
|
||||
throwIfEventEmitterPayloadTypeIsUnsupported(
|
||||
moduleName,
|
||||
undefined,
|
||||
'onBuffer',
|
||||
{type: 'ArrayBufferTypeAnnotation'},
|
||||
);
|
||||
}).toThrow(UnsupportedModuleEventEmitterPayloadTypeParserError);
|
||||
});
|
||||
|
||||
it('does not throw the error if the payload is a supported type', () => {
|
||||
expect(() => {
|
||||
throwIfEventEmitterPayloadTypeIsUnsupported(
|
||||
moduleName,
|
||||
undefined,
|
||||
'onCount',
|
||||
{type: 'DoubleTypeAnnotation'},
|
||||
);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('throwIfPartialNotAnnotatingTypeParameter', () => {
|
||||
const flowParser = new FlowParser();
|
||||
const typescriptParser = new TypeScriptParser();
|
||||
|
||||
@@ -27,6 +27,7 @@ const {
|
||||
UnsupportedArrayElementTypeAnnotationParserError,
|
||||
UnsupportedFunctionParamTypeAnnotationParserError,
|
||||
UnsupportedFunctionReturnTypeAnnotationParserError,
|
||||
UnsupportedModuleEventEmitterPayloadTypeParserError,
|
||||
UnsupportedModuleEventEmitterPropertyParserError,
|
||||
UnsupportedModuleEventEmitterTypePropertyParserError,
|
||||
UnsupportedModulePropertyParserError,
|
||||
@@ -196,6 +197,25 @@ function throwIfEventEmitterEventTypeIsUnsupported(
|
||||
}
|
||||
}
|
||||
|
||||
// ArrayBuffer is not emittable on any platform: Android emitters always carry a
|
||||
// folly::dynamic payload, which cannot hold raw bytes, and neither the ObjC nor
|
||||
// the C++ emitter contract can hand out a buffer that outlives the emit call.
|
||||
function throwIfEventEmitterPayloadTypeIsUnsupported(
|
||||
nativeModuleName: string,
|
||||
propertyValue: $FlowFixMe,
|
||||
propertyName: string,
|
||||
payloadTypeAnnotation: NativeModuleTypeAnnotation,
|
||||
) {
|
||||
if (payloadTypeAnnotation.type === 'ArrayBufferTypeAnnotation') {
|
||||
throw new UnsupportedModuleEventEmitterPayloadTypeParserError(
|
||||
nativeModuleName,
|
||||
propertyValue,
|
||||
propertyName,
|
||||
'ArrayBuffer',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function throwIfModuleTypeIsUnsupported(
|
||||
nativeModuleName: string,
|
||||
propertyValue: $FlowFixMe,
|
||||
@@ -418,6 +438,7 @@ module.exports = {
|
||||
throwIfUntypedModule,
|
||||
throwIfEventEmitterTypeIsUnsupported,
|
||||
throwIfEventEmitterEventTypeIsUnsupported,
|
||||
throwIfEventEmitterPayloadTypeIsUnsupported,
|
||||
throwIfModuleTypeIsUnsupported,
|
||||
throwIfMoreThanOneModuleInterfaceParserError,
|
||||
throwIfUnsupportedFunctionParamTypeAnnotationParserError,
|
||||
|
||||
@@ -111,6 +111,21 @@ class UnsupportedModuleEventEmitterPropertyParserError extends ParserError {
|
||||
}
|
||||
}
|
||||
|
||||
class UnsupportedModuleEventEmitterPayloadTypeParserError extends ParserError {
|
||||
constructor(
|
||||
nativeModuleName: string,
|
||||
propertyValue: $FlowFixMe,
|
||||
propertyName: string,
|
||||
payloadType: string,
|
||||
) {
|
||||
super(
|
||||
nativeModuleName,
|
||||
propertyValue,
|
||||
`EventEmitter '${propertyName}' cannot have payload type '${payloadType}'.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UnsupportedModulePropertyParserError extends ParserError {
|
||||
constructor(
|
||||
nativeModuleName: string,
|
||||
@@ -456,6 +471,7 @@ module.exports = {
|
||||
UnsupportedEnumDeclarationParserError,
|
||||
UnsupportedModuleEventEmitterTypePropertyParserError,
|
||||
UnsupportedModuleEventEmitterPropertyParserError,
|
||||
UnsupportedModuleEventEmitterPayloadTypeParserError,
|
||||
UnsupportedModulePropertyParserError,
|
||||
UnsupportedObjectPropertyTypeAnnotationParserError,
|
||||
UnsupportedObjectPropertyWithIndexerTypeAnnotationParserError,
|
||||
|
||||
+26
@@ -350,6 +350,31 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
const NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_EVENT_EMITTER = `
|
||||
/**
|
||||
* 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 type {EventEmitter} from '../CodegenTypes';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+onBuffer: EventEmitter<ArrayBuffer>;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
NATIVE_MODULES_WITH_READ_ONLY_OBJECT_NO_TYPE_FOR_CONTENT,
|
||||
NATIVE_MODULES_WITH_UNNAMED_PARAMS,
|
||||
@@ -364,4 +389,5 @@ module.exports = {
|
||||
NUMERIC_VALUES_ENUM_NATIVE_MODULE,
|
||||
MAP_WITH_EXTRA_KEYS_NATIVE_MODULE,
|
||||
NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_OBJECT_PROPERTY,
|
||||
NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_EVENT_EMITTER,
|
||||
};
|
||||
|
||||
+4
-1
@@ -667,7 +667,7 @@ const NATIVE_MODULE_WITH_EVENT_EMITTERS = `
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import type {EventEmitter} from '../CodegenTypes';
|
||||
import type {Double, EventEmitter, Float, Int32} from '../CodegenTypes';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export type ObjectStruct = {
|
||||
@@ -686,6 +686,9 @@ export interface Spec extends TurboModule {
|
||||
+onEvent5: EventEmitter<ObjectStruct>;
|
||||
+onEvent6: EventEmitter<ObjectStruct[]>;
|
||||
+onEvent7: EventEmitter<MappedObject>;
|
||||
+onEvent8: EventEmitter<Double>;
|
||||
+onEvent9: EventEmitter<Float>;
|
||||
+onEvent10: EventEmitter<Int32>;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
+32
@@ -6,6 +6,8 @@ exports[`RN Codegen Flow Parser Fails with error message MAP_WITH_EXTRA_KEYS_NAT
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message MIXED_VALUES_ENUM_NATIVE_MODULE 1`] = `"Module NativeSampleTurboModule: Failed parsing the enum SomeEnum in NativeSampleTurboModule with the error: Enums can not be mixed- they all must be either blank, number, or string values."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_EVENT_EMITTER 1`] = `"Module NativeSampleTurboModule: EventEmitter 'onBuffer' cannot have payload type 'ArrayBuffer'."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_OBJECT_PROPERTY 1`] = `"Module NativeSampleTurboModule: Object property '[object Object]' cannot have type 'ArrayBuffer'."`;
|
||||
|
||||
exports[`RN Codegen Flow Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_WITH_NO_TYPE_FOR_CONTENT 1`] = `"Module NativeSampleTurboModule: Generic 'Array' must have type parameters."`;
|
||||
@@ -2119,6 +2121,36 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_EVENT_EM
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent8',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'DoubleTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent9',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'FloatTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent10',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'Int32TypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'methods': []
|
||||
|
||||
@@ -42,6 +42,7 @@ import type {
|
||||
const {
|
||||
throwIfConfigNotfound,
|
||||
throwIfEventEmitterEventTypeIsUnsupported,
|
||||
throwIfEventEmitterPayloadTypeIsUnsupported,
|
||||
throwIfEventEmitterTypeIsUnsupported,
|
||||
throwIfIncorrectModuleRegistryCallArgument,
|
||||
throwIfIncorrectModuleRegistryCallTypeParameterParserError,
|
||||
@@ -551,6 +552,13 @@ function buildEventEmitterSchema(
|
||||
parser,
|
||||
);
|
||||
|
||||
throwIfEventEmitterPayloadTypeIsUnsupported(
|
||||
hasteModuleName,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
key.name,
|
||||
eventTypeAnnotation,
|
||||
);
|
||||
|
||||
return {
|
||||
name: eventemitterName,
|
||||
optional: Boolean(property.optional),
|
||||
|
||||
+22
@@ -286,6 +286,27 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
const NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_EVENT_EMITTER = `
|
||||
/**
|
||||
* 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 onBuffer: EventEmitter<ArrayBuffer>;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
module.exports = {
|
||||
NATIVE_MODULES_WITH_UNNAMED_PARAMS,
|
||||
NATIVE_MODULES_WITH_PROMISE_WITHOUT_TYPE,
|
||||
@@ -299,4 +320,5 @@ module.exports = {
|
||||
NUMERIC_VALUES_ENUM_NATIVE_MODULE,
|
||||
MAP_WITH_EXTRA_KEYS_NATIVE_MODULE,
|
||||
NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_OBJECT_PROPERTY,
|
||||
NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_EVENT_EMITTER,
|
||||
};
|
||||
|
||||
+4
@@ -766,6 +766,7 @@ const NATIVE_MODULE_WITH_EVENT_EMITTERS = `
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import type {Double, Float, Int32} from 'react-native/Libraries/Types/CodegenTypes';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export type ObjectStruct = {
|
||||
@@ -784,6 +785,9 @@ export interface Spec extends TurboModule {
|
||||
readonly onEvent5: EventEmitter<ObjectStruct>;
|
||||
readonly onEvent6: EventEmitter<ObjectStruct[]>;
|
||||
readonly onEvent7: EventEmitter<MappedObject>;
|
||||
readonly onEvent8: EventEmitter<Double>;
|
||||
readonly onEvent9: EventEmitter<Float>;
|
||||
readonly onEvent10: EventEmitter<Int32>;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
+32
@@ -6,6 +6,8 @@ exports[`RN Codegen TypeScript Parser Fails with error message MAP_WITH_EXTRA_KE
|
||||
|
||||
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_BUFFER_IN_EVENT_EMITTER 1`] = `"Module NativeSampleTurboModule: EventEmitter 'onBuffer' cannot have payload type 'ArrayBuffer'."`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser Fails with error message NATIVE_MODULES_WITH_ARRAY_BUFFER_IN_OBJECT_PROPERTY 1`] = `"Module NativeSampleTurboModule: Object property '[object Object]' cannot have type 'ArrayBuffer'."`;
|
||||
|
||||
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."`;
|
||||
@@ -2343,6 +2345,36 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_EV
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent8',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'DoubleTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent9',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'FloatTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent10',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'Int32TypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'methods': []
|
||||
|
||||
Reference in New Issue
Block a user