create-expo-cljs-app
Version:
Create a react native application with Expo and Shadow-CLJS!
264 lines (227 loc) • 6.88 kB
JavaScript
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
;
const nullthrows = require('nullthrows');
const _require = require('./CppHelpers.js'),
getCppTypeForAnnotation = _require.getCppTypeForAnnotation,
toSafeCppString = _require.toSafeCppString,
generateEventStructName = _require.generateEventStructName;
const template = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* ${'@'}generated by codegen project: GenerateEventEmitterH.js
*/
#pragma once
#include <react/renderer/components/view/ViewEventEmitter.h>
namespace facebook {
namespace react {
::_COMPONENT_EMITTERS_::
} // namespace react
} // namespace facebook
`;
const componentTemplate = `
class ::_CLASSNAME_::EventEmitter : public ViewEventEmitter {
public:
using ViewEventEmitter::ViewEventEmitter;
::_STRUCTS_::
::_EVENTS_::
};
`.trim();
const structTemplate = `
struct ::_STRUCT_NAME_:: {
::_FIELDS_::
};
`.trim();
const enumTemplate = `enum class ::_ENUM_NAME_:: {
::_VALUES_::
};
static char const *toString(const ::_ENUM_NAME_:: value) {
switch (value) {
::_TO_CASES_::
}
}
`.trim();
function indent(nice, spaces) {
return nice
.split('\n')
.map((line, index) => {
if (line.length === 0 || index === 0) {
return line;
}
const emptySpaces = new Array(spaces + 1).join(' ');
return emptySpaces + line;
})
.join('\n');
}
function getNativeTypeFromAnnotation(componentName, eventProperty, nameParts) {
const type = eventProperty.typeAnnotation.type;
switch (type) {
case 'BooleanTypeAnnotation':
case 'StringTypeAnnotation':
case 'Int32TypeAnnotation':
case 'DoubleTypeAnnotation':
case 'FloatTypeAnnotation':
return getCppTypeForAnnotation(type);
case 'StringEnumTypeAnnotation':
return generateEventStructName(nameParts.concat([eventProperty.name]));
case 'ObjectTypeAnnotation':
return generateEventStructName(nameParts.concat([eventProperty.name]));
default:
type;
throw new Error(`Received invalid event property type ${type}`);
}
}
function generateEnum(structs, options, nameParts) {
const structName = generateEventStructName(nameParts);
const fields = options
.map((option, index) => `${toSafeCppString(option)}`)
.join(',\n ');
const toCases = options
.map(
option =>
`case ${structName}::${toSafeCppString(option)}: return "${option}";`,
)
.join('\n' + ' ');
structs.set(
structName,
enumTemplate
.replace(/::_ENUM_NAME_::/g, structName)
.replace('::_VALUES_::', fields)
.replace('::_TO_CASES_::', toCases),
);
}
function generateStruct(structs, componentName, nameParts, properties) {
const structNameParts = nameParts;
const structName = generateEventStructName(structNameParts);
const fields = properties
.map(property => {
return `${getNativeTypeFromAnnotation(
componentName,
property,
structNameParts,
)} ${property.name};`;
})
.join('\n' + ' ');
properties.forEach(property => {
const name = property.name,
typeAnnotation = property.typeAnnotation;
switch (typeAnnotation.type) {
case 'BooleanTypeAnnotation':
return;
case 'StringTypeAnnotation':
return;
case 'Int32TypeAnnotation':
return;
case 'DoubleTypeAnnotation':
return;
case 'FloatTypeAnnotation':
return;
case 'ObjectTypeAnnotation':
generateStruct(
structs,
componentName,
nameParts.concat([name]),
nullthrows(typeAnnotation.properties),
);
return;
case 'StringEnumTypeAnnotation':
generateEnum(structs, typeAnnotation.options, nameParts.concat([name]));
return;
default:
typeAnnotation.type;
throw new Error(
`Received invalid event property type ${typeAnnotation.type}`,
);
}
});
structs.set(
structName,
structTemplate
.replace('::_STRUCT_NAME_::', structName)
.replace('::_FIELDS_::', fields),
);
}
function generateStructs(componentName, component) {
const structs = new Map();
component.events.forEach(event => {
if (event.typeAnnotation.argument) {
generateStruct(
structs,
componentName,
[event.name],
event.typeAnnotation.argument.properties,
);
}
});
return Array.from(structs.values()).join('\n\n');
}
function generateEvent(componentName, event) {
if (event.typeAnnotation.argument) {
const structName = generateEventStructName([event.name]);
return `void ${event.name}(${structName} value) const;`;
}
return `void ${event.name}() const;`;
}
function generateEvents(componentName, component) {
return component.events
.map(event => generateEvent(componentName, event))
.join('\n\n' + ' ');
}
module.exports = {
generate(libraryName, schema, moduleSpecName, packageName) {
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 moduleComponentsWithEvents = Object.keys(moduleComponents).filter(
componentName => moduleComponents[componentName].events.length > 0,
);
const fileName = 'EventEmitters.h';
const componentEmitters =
moduleComponentsWithEvents.length > 0
? Object.keys(moduleComponents)
.map(componentName => {
const component = moduleComponents[componentName];
const replacedTemplate = componentTemplate
.replace(/::_CLASSNAME_::/g, componentName)
.replace(
'::_STRUCTS_::',
indent(generateStructs(componentName, component), 2),
)
.replace(
'::_EVENTS_::',
generateEvents(componentName, component),
)
.trim();
return replacedTemplate;
})
.join('\n')
: '';
const replacedTemplate = template.replace(
/::_COMPONENT_EMITTERS_::/g,
componentEmitters,
);
return new Map([[fileName, replacedTemplate]]);
},
};