Add support for enum event arguments

Summary:
This diff adds codegen support for event arguments such as:

```
type Event = $ReadOnly<{|
    orientation: ('portrait' | 'landscape'),
|}>;
```

Facebook
 #noautofix

Reviewed By: shergin

Differential Revision: D15769046

fbshipit-source-id: b2ad8d044b06c2394a9aa75a198ea504672cde68
This commit is contained in:
Rick Hanlon
2019-06-18 06:32:31 -07:00
committed by Facebook Github Bot
parent 23df1b09a8
commit 2deb39b8f6
11 changed files with 1078 additions and 2 deletions
+8
View File
@@ -31,6 +31,14 @@ export type ObjectPropertyType =
name: string,
optional: boolean,
|}>
| $ReadOnly<{|
type: 'StringEnumTypeAnnotation',
name: string,
optional: boolean,
options: $ReadOnlyArray<{|
name: string,
|}>,
|}>
| $ReadOnly<{|
type: 'ObjectTypeAnnotation',
name: string,
@@ -70,6 +70,15 @@ function generateSetter(variableName, propertyName, propertyParts) {
return `${variableName}.setProperty(runtime, "${propertyName}", ${eventChain}`;
}
function generateEnumSetter(variableName, propertyName, propertyParts) {
const trailingPeriod = propertyParts.length === 0 ? '' : '.';
const eventChain = `event.${propertyParts.join(
'.',
)}${trailingPeriod}${propertyName})`;
return `${variableName}.setProperty(runtime, "${propertyName}", toString(${eventChain});`;
}
function generateSetters(
parentPropertyName: string,
properties: $ReadOnlyArray<ObjectPropertyType>,
@@ -87,6 +96,12 @@ function generateSetters(
eventProperty.name,
propertyParts,
);
case 'StringEnumTypeAnnotation':
return generateEnumSetter(
parentPropertyName,
eventProperty.name,
propertyParts,
);
case 'ObjectTypeAnnotation':
const propertyName = eventProperty.name;
return `
@@ -12,7 +12,7 @@
const nullthrows = require('nullthrows');
const {getCppTypeForAnnotation} = require('./CppHelpers.js');
const {getCppTypeForAnnotation, toSafeCppString} = require('./CppHelpers.js');
const {generateStructName} = require('./EventEmitterHelpers.js');
import type {
@@ -67,6 +67,16 @@ struct ::_STRUCT_NAME_:: {
};
`.trim();
const enumTemplate = `enum class ::_ENUM_NAME_:: {
::_VALUES_::
};
inline char const *toString(const ::_ENUM_NAME_:: value) {
switch (value) {
::_TO_CASES_::
}
}`.trim();
function getNativeTypeFromAnnotation(
componentName: string,
eventProperty: ObjectPropertyType,
@@ -80,6 +90,11 @@ function getNativeTypeFromAnnotation(
case 'Int32TypeAnnotation':
case 'FloatTypeAnnotation':
return getCppTypeForAnnotation(type);
case 'StringEnumTypeAnnotation':
return generateStructName(
componentName,
nameParts.concat([eventProperty.name]),
);
case 'ObjectTypeAnnotation':
return generateStructName(
componentName,
@@ -90,6 +105,29 @@ function getNativeTypeFromAnnotation(
throw new Error(`Receieved invalid event property type ${type}`);
}
}
function generateEnum(structs, componentName, options, nameParts) {
const structName = generateStructName(componentName, nameParts);
const fields = options
.map((option, index) => `${toSafeCppString(option.name)}`)
.join(',\n ');
const toCases = options
.map(
option =>
`case ${structName}::${toSafeCppString(option.name)}: return "${
option.name
}";`,
)
.join('\n' + ' ');
structs.set(
structName,
enumTemplate
.replace(/::_ENUM_NAME_::/g, structName)
.replace('::_VALUES_::', fields)
.replace('::_TO_CASES_::', toCases),
);
}
function generateStruct(
structs: StructsMap,
@@ -126,6 +164,14 @@ function generateStruct(
nullthrows(property.properties),
);
return;
case 'StringEnumTypeAnnotation':
generateEnum(
structs,
componentName,
property.options,
nameParts.concat([name]),
);
return;
default:
(property: empty);
throw new Error(
@@ -587,6 +587,32 @@ const EVENT_PROPS: SchemaType = {
},
},
},
{
name: 'onOrientationChange',
optional: true,
bubblingType: 'direct',
typeAnnotation: {
type: 'EventTypeAnnotation',
argument: {
type: 'ObjectTypeAnnotation',
properties: [
{
type: 'StringEnumTypeAnnotation',
name: 'orientation',
optional: false,
options: [
{
name: 'landscape',
},
{
name: 'portrait',
},
],
},
],
},
},
},
{
name: 'onEnd',
optional: true,
@@ -165,6 +165,13 @@ void EventsNativeComponentEventEmitter::onEventDirect(EventsNativeComponentOnEve
return payload;
});
}
void EventsNativeComponentEventEmitter::onOrientationChange(EventsNativeComponentOnOrientationChangeStruct event) const {
dispatchEvent(\\"orientationChange\\", [event=std::move(event)](jsi::Runtime &runtime) {
auto payload = jsi::Object(runtime);
payload.setProperty(runtime, \\"orientation\\", toString(event.orientation));
return payload;
});
}
void EventsNativeComponentEventEmitter::onEnd() const {
dispatchEvent(\\"end\\");
}
@@ -166,6 +166,22 @@ struct EventsNativeComponentOnEventDirectStruct {
bool value;
};
enum class EventsNativeComponentOnOrientationChangeOrientationStruct {
Landscape,
Portrait
};
inline char const *toString(const EventsNativeComponentOnOrientationChangeOrientationStruct value) {
switch (value) {
case EventsNativeComponentOnOrientationChangeOrientationStruct::Landscape: return \\"landscape\\";
case EventsNativeComponentOnOrientationChangeOrientationStruct::Portrait: return \\"portrait\\";
}
}
struct EventsNativeComponentOnOrientationChangeStruct {
EventsNativeComponentOnOrientationChangeOrientationStruct orientation;
};
class EventsNativeComponentEventEmitter : public ViewEventEmitter {
public:
using ViewEventEmitter::ViewEventEmitter;
@@ -174,6 +190,8 @@ class EventsNativeComponentEventEmitter : public ViewEventEmitter {
void onEventDirect(EventsNativeComponentOnEventDirectStruct value) const;
void onOrientationChange(EventsNativeComponentOnOrientationChangeStruct value) const;
void onEnd() const;
};
@@ -221,12 +221,17 @@ const EventsNativeComponentViewConfig = {
topEventDirect: {
registrationName: 'onEventDirect',
},
topOrientationChange: {
registrationName: 'onOrientationChange',
},
},
validAttributes: {
disabled: true,
onChange: true,
onEventDirect: true,
onOrientationChange: true,
onEnd: true,
},
};
@@ -30,6 +30,11 @@ const EVENT_DEFINITION = `
int32_optional_value: ?Int32,
int32_optional_both?: ?Int32,
enum_required: ('small' | 'large'),
enum_optional_key?: ('small' | 'large'),
enum_optional_value: ?('small' | 'large'),
enum_optional_both?: ?('small' | 'large'),
object_required: {
boolean_required: boolean,
}
+9 -1
View File
@@ -50,8 +50,16 @@ function getPropertyType(name, optional, typeAnnotation) {
optional,
properties: typeAnnotation.properties.map(buildPropertiesForEvent),
};
case 'UnionTypeAnnotation':
return {
type: 'StringEnumTypeAnnotation',
name,
optional,
options: typeAnnotation.types.map(option => ({name: option.value})),
};
default:
throw new Error(`Unable to determine type for "${name}"`);
(type: empty);
throw new Error(`Unable to determine event type for "${name}"`);
}
}
@@ -79,6 +79,7 @@ function getTypeAnnotationForArray(name, typeAnnotation, defaultValue) {
options: typeAnnotation.types.map(option => ({name: option.value})),
};
default:
(type: empty);
throw new Error(`Unknown prop type for "${name}"`);
}
}
@@ -177,6 +178,7 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) {
}
throw new Error(`A default enum value is required for "${name}"`);
default:
(type: empty);
throw new Error(`Unknown prop type for "${name}"`);
}
}