mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary:
## Changes
{| ... |} -> { ... }
**Motivation:** In Flow, object literals are exact by default. So, there's no need for the pipes. Also: Now, the syntax for object literals is consistent across react-native-codegen.
Changelog: [Internal]
Reviewed By: hramos
Differential Revision: D24774771
fbshipit-source-id: 24ceb6f5876122aa8ad9e08c7e903215864ad6f5
257 lines
7.3 KiB
JavaScript
257 lines
7.3 KiB
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.
|
|
*
|
|
* @flow strict
|
|
* @format
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const {
|
|
capitalize,
|
|
getSafePropertyName,
|
|
getNamespacedStructName,
|
|
} = require('../Utils');
|
|
|
|
import type {Nullable} from '../../../../CodegenSchema';
|
|
import type {StructTypeAnnotation, RegularStruct} from '../StructCollector';
|
|
import type {StructSerilizationOutput} from './serializeStruct';
|
|
|
|
const {unwrapNullable} = require('../../../../parsers/flow/modules/utils');
|
|
|
|
const StructTemplate = ({
|
|
hasteModuleName,
|
|
structName,
|
|
structProperties,
|
|
}: $ReadOnly<{
|
|
hasteModuleName: string,
|
|
structName: string,
|
|
structProperties: string,
|
|
}>) => `namespace JS {
|
|
namespace ${hasteModuleName} {
|
|
struct ${structName} {
|
|
${structProperties}
|
|
|
|
${structName}(NSDictionary *const v) : _v(v) {}
|
|
private:
|
|
NSDictionary *_v;
|
|
};
|
|
}
|
|
}
|
|
|
|
@interface RCTCxxConvert (${hasteModuleName}_${structName})
|
|
+ (RCTManagedPointer *)JS_${hasteModuleName}_${structName}:(id)json;
|
|
@end`;
|
|
|
|
const MethodTemplate = ({
|
|
returnType,
|
|
returnValue,
|
|
hasteModuleName,
|
|
structName,
|
|
propertyName,
|
|
}: $ReadOnly<{
|
|
returnType: string,
|
|
returnValue: string,
|
|
hasteModuleName: string,
|
|
structName: string,
|
|
propertyName: string,
|
|
}>) => `inline ${returnType}JS::${hasteModuleName}::${structName}::${propertyName}() const
|
|
{
|
|
id const p = _v[@"${propertyName}"];
|
|
return ${returnValue};
|
|
}`;
|
|
|
|
function toObjCType(
|
|
hasteModuleName: string,
|
|
nullableTypeAnnotation: Nullable<StructTypeAnnotation>,
|
|
isOptional: boolean = false,
|
|
): string {
|
|
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
|
|
const isRequired = !nullable && !isOptional;
|
|
const wrapFollyOptional = (type: string) => {
|
|
return isRequired ? type : `folly::Optional<${type}>`;
|
|
};
|
|
|
|
switch (typeAnnotation.type) {
|
|
case 'ReservedTypeAnnotation':
|
|
switch (typeAnnotation.name) {
|
|
case 'RootTag':
|
|
return wrapFollyOptional('double');
|
|
default:
|
|
(typeAnnotation.name: empty);
|
|
throw new Error(`Unknown prop type, found: ${typeAnnotation.name}"`);
|
|
}
|
|
case 'StringTypeAnnotation':
|
|
return 'NSString *';
|
|
case 'NumberTypeAnnotation':
|
|
return wrapFollyOptional('double');
|
|
case 'FloatTypeAnnotation':
|
|
return wrapFollyOptional('double');
|
|
case 'Int32TypeAnnotation':
|
|
return wrapFollyOptional('double');
|
|
case 'DoubleTypeAnnotation':
|
|
return wrapFollyOptional('double');
|
|
case 'BooleanTypeAnnotation':
|
|
return wrapFollyOptional('bool');
|
|
case 'GenericObjectTypeAnnotation':
|
|
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable';
|
|
case 'ArrayTypeAnnotation':
|
|
if (typeAnnotation.elementType == null) {
|
|
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable';
|
|
}
|
|
return wrapFollyOptional(
|
|
`facebook::react::LazyVector<${toObjCType(
|
|
hasteModuleName,
|
|
typeAnnotation.elementType,
|
|
)}>`,
|
|
);
|
|
case 'TypeAliasTypeAnnotation':
|
|
const structName = capitalize(typeAnnotation.name);
|
|
const namespacedStructName = getNamespacedStructName(
|
|
hasteModuleName,
|
|
structName,
|
|
);
|
|
return wrapFollyOptional(namespacedStructName);
|
|
default:
|
|
(typeAnnotation.type: empty);
|
|
throw new Error(
|
|
`Couldn't convert into ObjC type: ${typeAnnotation.type}"`,
|
|
);
|
|
}
|
|
}
|
|
|
|
function toObjCValue(
|
|
hasteModuleName: string,
|
|
nullableTypeAnnotation: Nullable<StructTypeAnnotation>,
|
|
value: string,
|
|
depth: number,
|
|
isOptional: boolean = false,
|
|
): string {
|
|
const [typeAnnotation, nullable] = unwrapNullable(nullableTypeAnnotation);
|
|
const isRequired = !nullable && !isOptional;
|
|
const RCTBridgingTo = (type: string, arg?: string) => {
|
|
const args = [value, arg].filter(Boolean).join(', ');
|
|
return isRequired
|
|
? `RCTBridgingTo${type}(${args})`
|
|
: `RCTBridgingToOptional${type}(${args})`;
|
|
};
|
|
|
|
switch (typeAnnotation.type) {
|
|
case 'ReservedTypeAnnotation':
|
|
switch (typeAnnotation.name) {
|
|
case 'RootTag':
|
|
return RCTBridgingTo('Double');
|
|
default:
|
|
(typeAnnotation.name: empty);
|
|
throw new Error(
|
|
`Couldn't convert into ObjC type: ${typeAnnotation.type}"`,
|
|
);
|
|
}
|
|
case 'StringTypeAnnotation':
|
|
return RCTBridgingTo('String');
|
|
case 'NumberTypeAnnotation':
|
|
return RCTBridgingTo('Double');
|
|
case 'FloatTypeAnnotation':
|
|
return RCTBridgingTo('Double');
|
|
case 'Int32TypeAnnotation':
|
|
return RCTBridgingTo('Double');
|
|
case 'DoubleTypeAnnotation':
|
|
return RCTBridgingTo('Double');
|
|
case 'BooleanTypeAnnotation':
|
|
return RCTBridgingTo('Bool');
|
|
case 'GenericObjectTypeAnnotation':
|
|
return value;
|
|
case 'ArrayTypeAnnotation':
|
|
const {elementType} = typeAnnotation;
|
|
if (elementType == null) {
|
|
return value;
|
|
}
|
|
|
|
const localVarName = `itemValue_${depth}`;
|
|
const elementObjCType = toObjCType(hasteModuleName, elementType);
|
|
const elementObjCValue = toObjCValue(
|
|
hasteModuleName,
|
|
elementType,
|
|
localVarName,
|
|
depth + 1,
|
|
);
|
|
|
|
return RCTBridgingTo(
|
|
'Vec',
|
|
`^${elementObjCType}(id ${localVarName}) { return ${elementObjCValue}; }`,
|
|
);
|
|
case 'TypeAliasTypeAnnotation':
|
|
const structName = capitalize(typeAnnotation.name);
|
|
const namespacedStructName = getNamespacedStructName(
|
|
hasteModuleName,
|
|
structName,
|
|
);
|
|
|
|
return !isRequired
|
|
? `(${value} == nil ? folly::none : folly::make_optional(${namespacedStructName}(${value})))`
|
|
: `${namespacedStructName}(${value})`;
|
|
default:
|
|
(typeAnnotation.type: empty);
|
|
throw new Error(
|
|
`Couldn't convert into ObjC value: ${typeAnnotation.type}"`,
|
|
);
|
|
}
|
|
}
|
|
|
|
function serializeRegularStruct(
|
|
hasteModuleName: string,
|
|
struct: RegularStruct,
|
|
): StructSerilizationOutput {
|
|
const declaration = StructTemplate({
|
|
hasteModuleName: hasteModuleName,
|
|
structName: struct.name,
|
|
structProperties: struct.properties
|
|
.map(property => {
|
|
const {typeAnnotation, optional} = property;
|
|
const propName = getSafePropertyName(property);
|
|
const returnType = toObjCType(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
optional,
|
|
);
|
|
|
|
const padding = ' '.repeat(returnType.endsWith('*') ? 0 : 1);
|
|
return `${returnType}${padding}${propName}() const;`;
|
|
})
|
|
.join('\n '),
|
|
});
|
|
|
|
const methods = struct.properties
|
|
.map<string>(property => {
|
|
const {typeAnnotation, optional} = property;
|
|
const propName = getSafePropertyName(property);
|
|
const returnType = toObjCType(hasteModuleName, typeAnnotation, optional);
|
|
const returnValue = toObjCValue(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
'p',
|
|
0,
|
|
optional,
|
|
);
|
|
|
|
const padding = ' '.repeat(returnType.endsWith('*') ? 0 : 1);
|
|
return MethodTemplate({
|
|
hasteModuleName,
|
|
structName: struct.name,
|
|
returnType: returnType + padding,
|
|
returnValue: returnValue,
|
|
propertyName: propName,
|
|
});
|
|
})
|
|
.join('\n');
|
|
|
|
return {methods, declaration};
|
|
}
|
|
|
|
module.exports = {
|
|
serializeRegularStruct,
|
|
};
|