UNPKG

create-expo-cljs-app

Version:

Create a react native application with Expo and Shadow-CLJS!

356 lines (296 loc) 9.5 kB
/** * 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 */ 'use strict'; function getOrdinalNumber(num) { switch (num) { case 1: return '1st'; case 2: return '2nd'; case 3: return '3rd'; } if (num <= 20) { return `${num}th`; } return 'unknown'; } const protocolTemplate = ` @protocol RCT::_COMPONENT_NAME_::ViewProtocol <NSObject> ::_METHODS_:: @end `.trim(); const commandHandlerIfCaseConvertArgTemplate = ` NSObject *arg::_ARG_NUMBER_:: = args[::_ARG_NUMBER_::]; #if RCT_DEBUG if (!RCTValidateTypeOfViewCommandArgument(arg::_ARG_NUMBER_::, ::_EXPECTED_KIND_::, @"::_EXPECTED_KIND_STRING_::", @"::_COMPONENT_NAME_::", commandName, @"::_ARG_NUMBER_STR_::")) { return; } #endif ::_ARG_CONVERSION_:: `.trim(); const commandHandlerIfCaseTemplate = ` if ([commandName isEqualToString:@"::_COMMAND_NAME_::"]) { #if RCT_DEBUG if ([args count] != ::_NUM_ARGS_::) { RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"::_COMPONENT_NAME_::", commandName, (int)[args count], ::_NUM_ARGS_::); return; } #endif ::_CONVERT_ARGS_:: ::_COMMAND_CALL_:: return; } `.trim(); const commandHandlerTemplate = ` RCT_EXTERN inline void RCT::_COMPONENT_NAME_::HandleCommand( id<RCT::_COMPONENT_NAME_::ViewProtocol> componentView, NSString const *commandName, NSArray const *args) { ::_IF_CASES_:: #if RCT_DEBUG RCTLogError(@"%@ received command %@, which is not a supported command.", @"::_COMPONENT_NAME_::", commandName); #endif } `.trim(); 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: GenerateComponentHObjCpp.js */ #import <Foundation/Foundation.h> #import <React/RCTDefines.h> #import <React/RCTLog.h> NS_ASSUME_NONNULL_BEGIN ::_COMPONENT_CONTENT_:: NS_ASSUME_NONNULL_END `.trim(); function getObjCParamType(param) { const typeAnnotation = param.typeAnnotation; switch (typeAnnotation.type) { case 'ReservedTypeAnnotation': switch (typeAnnotation.name) { case 'RootTag': return 'double'; default: typeAnnotation.name; throw new Error(`Receieved invalid type: ${typeAnnotation.name}`); } case 'BooleanTypeAnnotation': return 'BOOL'; case 'DoubleTypeAnnotation': return 'double'; case 'FloatTypeAnnotation': return 'float'; case 'Int32TypeAnnotation': return 'NSInteger'; case 'StringTypeAnnotation': return 'NSString *'; default: typeAnnotation.type; throw new Error('Received invalid param type annotation'); } } function getObjCExpectedKindParamType(param) { const typeAnnotation = param.typeAnnotation; switch (typeAnnotation.type) { case 'ReservedTypeAnnotation': switch (typeAnnotation.name) { case 'RootTag': return '[NSNumber class]'; default: typeAnnotation.name; throw new Error(`Receieved invalid type: ${typeAnnotation.name}`); } case 'BooleanTypeAnnotation': return '[NSNumber class]'; case 'DoubleTypeAnnotation': return '[NSNumber class]'; case 'FloatTypeAnnotation': return '[NSNumber class]'; case 'Int32TypeAnnotation': return '[NSNumber class]'; case 'StringTypeAnnotation': return '[NSString class]'; default: typeAnnotation.type; throw new Error('Received invalid param type annotation'); } } function getReadableExpectedKindParamType(param) { const typeAnnotation = param.typeAnnotation; switch (typeAnnotation.type) { case 'ReservedTypeAnnotation': switch (typeAnnotation.name) { case 'RootTag': return 'double'; default: typeAnnotation.name; throw new Error(`Receieved invalid type: ${typeAnnotation.name}`); } case 'BooleanTypeAnnotation': return 'boolean'; case 'DoubleTypeAnnotation': return 'double'; case 'FloatTypeAnnotation': return 'float'; case 'Int32TypeAnnotation': return 'number'; case 'StringTypeAnnotation': return 'string'; default: typeAnnotation.type; throw new Error('Received invalid param type annotation'); } } function getObjCRightHandAssignmentParamType(param, index) { const typeAnnotation = param.typeAnnotation; switch (typeAnnotation.type) { case 'ReservedTypeAnnotation': switch (typeAnnotation.name) { case 'RootTag': return `[(NSNumber *)arg${index} doubleValue]`; default: typeAnnotation.name; throw new Error(`Receieved invalid type: ${typeAnnotation.name}`); } case 'BooleanTypeAnnotation': return `[(NSNumber *)arg${index} boolValue]`; case 'DoubleTypeAnnotation': return `[(NSNumber *)arg${index} doubleValue]`; case 'FloatTypeAnnotation': return `[(NSNumber *)arg${index} floatValue]`; case 'Int32TypeAnnotation': return `[(NSNumber *)arg${index} intValue]`; case 'StringTypeAnnotation': return `(NSString *)arg${index}`; default: typeAnnotation.type; throw new Error('Received invalid param type annotation'); } } function generateProtocol(component, componentName) { const commands = component.commands .map(command => { const params = command.typeAnnotation.params; const paramString = params.length === 0 ? '' : params .map((param, index) => { const objCType = getObjCParamType(param); return `${index === 0 ? '' : param.name}:(${objCType})${ param.name }`; }) .join(' '); return `- (void)${command.name}${paramString};`; }) .join('\n') .trim(); return protocolTemplate .replace(/::_COMPONENT_NAME_::/g, componentName) .replace('::_METHODS_::', commands); } function generateConvertAndValidateParam(param, index, componentName) { const leftSideType = getObjCParamType(param); const expectedKind = getObjCExpectedKindParamType(param); const expectedKindString = getReadableExpectedKindParamType(param); const argConversion = `${leftSideType} ${ param.name } = ${getObjCRightHandAssignmentParamType(param, index)};`; return commandHandlerIfCaseConvertArgTemplate .replace(/::_COMPONENT_NAME_::/g, componentName) .replace('::_ARG_CONVERSION_::', argConversion) .replace(/::_ARG_NUMBER_::/g, '' + index) .replace('::_ARG_NUMBER_STR_::', getOrdinalNumber(index + 1)) .replace('::_EXPECTED_KIND_::', expectedKind) .replace('::_EXPECTED_KIND_STRING_::', expectedKindString); } function generateCommandIfCase(command, componentName) { const params = command.typeAnnotation.params; const convertArgs = params .map((param, index) => generateConvertAndValidateParam(param, index, componentName), ) .join('\n\n') .trim(); const commandCallArgs = params.length === 0 ? '' : params .map((param, index) => { return `${index === 0 ? '' : param.name}:${param.name}`; }) .join(' '); const commandCall = `[componentView ${command.name}${commandCallArgs}];`; return commandHandlerIfCaseTemplate .replace(/::_COMPONENT_NAME_::/g, componentName) .replace(/::_COMMAND_NAME_::/g, command.name) .replace(/::_NUM_ARGS_::/g, '' + params.length) .replace('::_CONVERT_ARGS_::', convertArgs) .replace('::_COMMAND_CALL_::', commandCall); } function generateCommandHandler(component, componentName) { if (component.commands.length === 0) { return null; } const ifCases = component.commands .map(command => generateCommandIfCase(command, componentName)) .join('\n\n'); return commandHandlerTemplate .replace(/::_COMPONENT_NAME_::/g, componentName) .replace('::_IF_CASES_::', ifCases); } module.exports = { generate(libraryName, schema, moduleSpecName, packageName) { const fileName = 'RCTComponentViewHelpers.h'; const componentContent = 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 Object.keys(components) .filter(componentName => { const component = components[componentName]; return !( component.excludedPlatforms && component.excludedPlatforms.includes('iOS') ); }) .map(componentName => { return [ generateProtocol(components[componentName], componentName), generateCommandHandler(components[componentName], componentName), ] .join('\n\n') .trim(); }) .join('\n\n'); }) .filter(Boolean) .join('\n\n'); const replacedTemplate = template.replace( '::_COMPONENT_CONTENT_::', componentContent, ); return new Map([[fileName, replacedTemplate]]); }, };