204 lines
6.2 KiB
JavaScript
204 lines
6.2 KiB
JavaScript
|
/**
|
||
|
* 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
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
const _require = require('./CppHelpers.js'),
|
||
|
generateEventStructName = _require.generateEventStructName;
|
||
|
const FileTemplate = ({events, libraryName}) => `
|
||
|
/**
|
||
|
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
||
|
*
|
||
|
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
||
|
* once the code is regenerated.
|
||
|
*
|
||
|
* ${'@'}generated by codegen project: GenerateEventEmitterCpp.js
|
||
|
*/
|
||
|
|
||
|
#include <react/renderer/components/${libraryName}/EventEmitters.h>
|
||
|
|
||
|
namespace facebook {
|
||
|
namespace react {
|
||
|
|
||
|
${events}
|
||
|
|
||
|
} // namespace react
|
||
|
} // namespace facebook
|
||
|
`;
|
||
|
const ComponentTemplate = ({
|
||
|
className,
|
||
|
eventName,
|
||
|
structName,
|
||
|
dispatchEventName,
|
||
|
implementation,
|
||
|
}) => {
|
||
|
const capture = implementation.includes('event')
|
||
|
? 'event=std::move(event)'
|
||
|
: '';
|
||
|
return `
|
||
|
void ${className}EventEmitter::${eventName}(${structName} event) const {
|
||
|
dispatchEvent("${dispatchEventName}", [${capture}](jsi::Runtime &runtime) {
|
||
|
${implementation}
|
||
|
});
|
||
|
}
|
||
|
`.trim();
|
||
|
};
|
||
|
const BasicComponentTemplate = ({className, eventName, dispatchEventName}) =>
|
||
|
`
|
||
|
void ${className}EventEmitter::${eventName}() const {
|
||
|
dispatchEvent("${dispatchEventName}");
|
||
|
}
|
||
|
`.trim();
|
||
|
function generateSetter(variableName, propertyName, propertyParts) {
|
||
|
const trailingPeriod = propertyParts.length === 0 ? '' : '.';
|
||
|
const eventChain = `event.${propertyParts.join(
|
||
|
'.',
|
||
|
)}${trailingPeriod}${propertyName});`;
|
||
|
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, properties, propertyParts) {
|
||
|
const propSetters = properties
|
||
|
.map(eventProperty => {
|
||
|
const typeAnnotation = eventProperty.typeAnnotation;
|
||
|
switch (typeAnnotation.type) {
|
||
|
case 'BooleanTypeAnnotation':
|
||
|
return generateSetter(
|
||
|
parentPropertyName,
|
||
|
eventProperty.name,
|
||
|
propertyParts,
|
||
|
);
|
||
|
case 'StringTypeAnnotation':
|
||
|
return generateSetter(
|
||
|
parentPropertyName,
|
||
|
eventProperty.name,
|
||
|
propertyParts,
|
||
|
);
|
||
|
case 'Int32TypeAnnotation':
|
||
|
return generateSetter(
|
||
|
parentPropertyName,
|
||
|
eventProperty.name,
|
||
|
propertyParts,
|
||
|
);
|
||
|
case 'DoubleTypeAnnotation':
|
||
|
return generateSetter(
|
||
|
parentPropertyName,
|
||
|
eventProperty.name,
|
||
|
propertyParts,
|
||
|
);
|
||
|
case 'FloatTypeAnnotation':
|
||
|
return generateSetter(
|
||
|
parentPropertyName,
|
||
|
eventProperty.name,
|
||
|
propertyParts,
|
||
|
);
|
||
|
case 'StringEnumTypeAnnotation':
|
||
|
return generateEnumSetter(
|
||
|
parentPropertyName,
|
||
|
eventProperty.name,
|
||
|
propertyParts,
|
||
|
);
|
||
|
case 'ObjectTypeAnnotation':
|
||
|
const propertyName = eventProperty.name;
|
||
|
return `
|
||
|
{
|
||
|
auto ${propertyName} = jsi::Object(runtime);
|
||
|
${generateSetters(
|
||
|
propertyName,
|
||
|
typeAnnotation.properties,
|
||
|
propertyParts.concat([propertyName]),
|
||
|
)}
|
||
|
|
||
|
${parentPropertyName}.setProperty(runtime, "${propertyName}", ${propertyName});
|
||
|
}
|
||
|
`.trim();
|
||
|
default:
|
||
|
typeAnnotation.type;
|
||
|
throw new Error('Received invalid event property type');
|
||
|
}
|
||
|
})
|
||
|
.join('\n');
|
||
|
return propSetters;
|
||
|
}
|
||
|
function generateEvent(componentName, event) {
|
||
|
// This is a gross hack necessary because native code is sending
|
||
|
// events named things like topChange to JS which is then converted back to
|
||
|
// call the onChange prop. We should be consistent throughout the system.
|
||
|
// In order to migrate to this new system we have to support the current
|
||
|
// naming scheme. We should delete this once we are able to control this name
|
||
|
// throughout the system.
|
||
|
const dispatchEventName = `${event.name[2].toLowerCase()}${event.name.slice(
|
||
|
3,
|
||
|
)}`;
|
||
|
if (event.typeAnnotation.argument) {
|
||
|
const implementation = `
|
||
|
auto payload = jsi::Object(runtime);
|
||
|
${generateSetters('payload', event.typeAnnotation.argument.properties, [])}
|
||
|
return payload;
|
||
|
`.trim();
|
||
|
if (!event.name.startsWith('on')) {
|
||
|
throw new Error('Expected the event name to start with `on`');
|
||
|
}
|
||
|
return ComponentTemplate({
|
||
|
className: componentName,
|
||
|
eventName: event.name,
|
||
|
dispatchEventName,
|
||
|
structName: generateEventStructName([event.name]),
|
||
|
implementation,
|
||
|
});
|
||
|
}
|
||
|
return BasicComponentTemplate({
|
||
|
className: componentName,
|
||
|
eventName: event.name,
|
||
|
dispatchEventName,
|
||
|
});
|
||
|
}
|
||
|
module.exports = {
|
||
|
generate(libraryName, schema, packageName, assumeNonnull = false) {
|
||
|
const moduleComponents = Object.keys(schema.modules)
|
||
|
.map(moduleName => {
|
||
|
const module = schema.modules[moduleName];
|
||
|
if (module.type !== 'Component') {
|
||
|
return;
|
||
|
}
|
||
|
const components = module.components;
|
||
|
// No components in this module
|
||
|
if (components == null) {
|
||
|
return null;
|
||
|
}
|
||
|
return components;
|
||
|
})
|
||
|
.filter(Boolean)
|
||
|
.reduce((acc, components) => Object.assign(acc, components), {});
|
||
|
const fileName = 'EventEmitters.cpp';
|
||
|
const componentEmitters = Object.keys(moduleComponents)
|
||
|
.map(componentName => {
|
||
|
const component = moduleComponents[componentName];
|
||
|
return component.events
|
||
|
.map(event => {
|
||
|
return generateEvent(componentName, event);
|
||
|
})
|
||
|
.join('\n');
|
||
|
})
|
||
|
.join('\n');
|
||
|
const replacedTemplate = FileTemplate({
|
||
|
libraryName,
|
||
|
events: componentEmitters,
|
||
|
});
|
||
|
return new Map([[fileName, replacedTemplate]]);
|
||
|
},
|
||
|
};
|