Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const {
getModules,
isArrayRecursiveMember,
isDirectRecursiveMember,
throwIfUnsupportedEventEmitterPayload,
} = require('./Utils');

type FilesOutput = Map<string, string>;
Expand Down Expand Up @@ -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`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const {parseValidUnionType, toPascalCase} = require('../Utils');
const {
createAliasResolver,
getModules,
throwIfUnsupportedEventEmitterPayload,
throwIfUnsupportedPromiseArrayBuffer,
} = require('./Utils');

Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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}`,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -39,6 +42,9 @@ function getEventEmitterTypeObjCType(
}
case 'NumberTypeAnnotation':
case 'NumberLiteralTypeAnnotation':
case 'DoubleTypeAnnotation':
case 'FloatTypeAnnotation':
case 'Int32TypeAnnotation':
return 'NSNumber *_Nonnull';
case 'BooleanTypeAnnotation':
case 'BooleanLiteralTypeAnnotation':
Expand All @@ -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}`,
);
Expand Down
19 changes: 19 additions & 0 deletions packages/react-native-codegen/src/generators/modules/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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/);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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/);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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/);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
Loading
Loading