798 lines
19 KiB
Plaintext
798 lines
19 KiB
Plaintext
/**
|
|
* 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.
|
|
*
|
|
* @flow strict
|
|
* @format
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
import type {
|
|
BooleanTypeAnnotation,
|
|
DoubleTypeAnnotation,
|
|
EventTypeAnnotation,
|
|
FloatTypeAnnotation,
|
|
Int32TypeAnnotation,
|
|
NamedShape,
|
|
NativeModuleAliasMap,
|
|
NativeModuleBaseTypeAnnotation,
|
|
NativeModuleEnumDeclaration,
|
|
NativeModuleEnumMap,
|
|
NativeModuleFunctionTypeAnnotation,
|
|
NativeModuleGenericObjectTypeAnnotation,
|
|
NativeModuleMixedTypeAnnotation,
|
|
NativeModuleNumberTypeAnnotation,
|
|
NativeModuleObjectTypeAnnotation,
|
|
NativeModulePromiseTypeAnnotation,
|
|
NativeModuleTypeAliasTypeAnnotation,
|
|
NativeModuleTypeAnnotation,
|
|
NativeModuleUnionTypeAnnotation,
|
|
Nullable,
|
|
NumberLiteralTypeAnnotation,
|
|
ObjectTypeAnnotation,
|
|
ReservedTypeAnnotation,
|
|
StringLiteralTypeAnnotation,
|
|
StringLiteralUnionTypeAnnotation,
|
|
StringTypeAnnotation,
|
|
VoidTypeAnnotation,
|
|
} from '../CodegenSchema';
|
|
import type {Parser} from './parser';
|
|
import type {
|
|
ParserErrorCapturer,
|
|
TypeDeclarationMap,
|
|
TypeResolutionStatus,
|
|
} from './utils';
|
|
|
|
const {
|
|
throwIfArrayElementTypeAnnotationIsUnsupported,
|
|
throwIfPartialNotAnnotatingTypeParameter,
|
|
throwIfPartialWithMoreParameter,
|
|
} = require('./error-utils');
|
|
const {
|
|
ParserError,
|
|
UnsupportedTypeAnnotationParserError,
|
|
UnsupportedUnionTypeAnnotationParserError,
|
|
} = require('./errors');
|
|
const {
|
|
assertGenericTypeAnnotationHasExactlyOneTypeParameter,
|
|
translateFunctionTypeAnnotation,
|
|
unwrapNullable,
|
|
wrapNullable,
|
|
} = require('./parsers-commons');
|
|
const {nullGuard} = require('./parsers-utils');
|
|
const {isModuleRegistryCall} = require('./utils');
|
|
|
|
function emitBoolean(nullable: boolean): Nullable<BooleanTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'BooleanTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitInt32(nullable: boolean): Nullable<Int32TypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'Int32TypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitInt32Prop(
|
|
name: string,
|
|
optional: boolean,
|
|
): NamedShape<Int32TypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'Int32TypeAnnotation',
|
|
},
|
|
};
|
|
}
|
|
|
|
function emitNumber(
|
|
nullable: boolean,
|
|
): Nullable<NativeModuleNumberTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'NumberTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitRootTag(nullable: boolean): Nullable<ReservedTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'ReservedTypeAnnotation',
|
|
name: 'RootTag',
|
|
});
|
|
}
|
|
|
|
function emitDouble(nullable: boolean): Nullable<DoubleTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'DoubleTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitDoubleProp(
|
|
name: string,
|
|
optional: boolean,
|
|
): NamedShape<DoubleTypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'DoubleTypeAnnotation',
|
|
},
|
|
};
|
|
}
|
|
|
|
function emitVoid(nullable: boolean): Nullable<VoidTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'VoidTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitStringish(nullable: boolean): Nullable<StringTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'StringTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitFunction(
|
|
nullable: boolean,
|
|
hasteModuleName: string,
|
|
typeAnnotation: $FlowFixMe,
|
|
types: TypeDeclarationMap,
|
|
aliasMap: {...NativeModuleAliasMap},
|
|
enumMap: {...NativeModuleEnumMap},
|
|
tryParse: ParserErrorCapturer,
|
|
cxxOnly: boolean,
|
|
translateTypeAnnotation: $FlowFixMe,
|
|
parser: Parser,
|
|
): Nullable<NativeModuleFunctionTypeAnnotation> {
|
|
const translateFunctionTypeAnnotationValue: NativeModuleFunctionTypeAnnotation =
|
|
translateFunctionTypeAnnotation(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
);
|
|
return wrapNullable(nullable, translateFunctionTypeAnnotationValue);
|
|
}
|
|
|
|
function emitMixed(
|
|
nullable: boolean,
|
|
): Nullable<NativeModuleMixedTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'MixedTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitNumberLiteral(
|
|
nullable: boolean,
|
|
value: number,
|
|
): Nullable<NumberLiteralTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'NumberLiteralTypeAnnotation',
|
|
value,
|
|
});
|
|
}
|
|
|
|
function emitString(nullable: boolean): Nullable<StringTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'StringTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitStringLiteral(
|
|
nullable: boolean,
|
|
value: string,
|
|
): Nullable<StringLiteralTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'StringLiteralTypeAnnotation',
|
|
value,
|
|
});
|
|
}
|
|
|
|
function emitStringProp(
|
|
name: string,
|
|
optional: boolean,
|
|
): NamedShape<StringTypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'StringTypeAnnotation',
|
|
},
|
|
};
|
|
}
|
|
|
|
function typeAliasResolution(
|
|
typeResolution: TypeResolutionStatus,
|
|
objectTypeAnnotation: ObjectTypeAnnotation<
|
|
Nullable<NativeModuleBaseTypeAnnotation>,
|
|
>,
|
|
aliasMap: {...NativeModuleAliasMap},
|
|
nullable: boolean,
|
|
):
|
|
| Nullable<NativeModuleTypeAliasTypeAnnotation>
|
|
| Nullable<ObjectTypeAnnotation<Nullable<NativeModuleBaseTypeAnnotation>>> {
|
|
if (!typeResolution.successful) {
|
|
return wrapNullable(nullable, objectTypeAnnotation);
|
|
}
|
|
|
|
/**
|
|
* All aliases RHS are required.
|
|
*/
|
|
aliasMap[typeResolution.name] = objectTypeAnnotation;
|
|
|
|
/**
|
|
* Nullability of type aliases is transitive.
|
|
*
|
|
* Consider this case:
|
|
*
|
|
* type Animal = ?{
|
|
* name: string,
|
|
* };
|
|
*
|
|
* type B = Animal
|
|
*
|
|
* export interface Spec extends TurboModule {
|
|
* +greet: (animal: B) => void;
|
|
* }
|
|
*
|
|
* In this case, we follow B to Animal, and then Animal to ?{name: string}.
|
|
*
|
|
* We:
|
|
* 1. Replace `+greet: (animal: B) => void;` with `+greet: (animal: ?Animal) => void;`,
|
|
* 2. Pretend that Animal = {name: string}.
|
|
*
|
|
* Why do we do this?
|
|
* 1. In ObjC, we need to generate a struct called Animal, not B.
|
|
* 2. This design is simpler than managing nullability within both the type alias usage, and the type alias RHS.
|
|
* 3. What does it mean for a C++ struct, which is what this type alias RHS will generate, to be nullable? ¯\_(ツ)_/¯
|
|
* Nullability is a concept that only makes sense when talking about instances (i.e: usages) of the C++ structs.
|
|
* Hence, it's better to manage nullability within the actual TypeAliasTypeAnnotation nodes, and not the
|
|
* associated ObjectTypeAnnotations.
|
|
*/
|
|
return wrapNullable(nullable, {
|
|
type: 'TypeAliasTypeAnnotation',
|
|
name: typeResolution.name,
|
|
});
|
|
}
|
|
|
|
function typeEnumResolution(
|
|
typeAnnotation: $FlowFixMe,
|
|
typeResolution: TypeResolutionStatus,
|
|
nullable: boolean,
|
|
hasteModuleName: string,
|
|
enumMap: {...NativeModuleEnumMap},
|
|
parser: Parser,
|
|
): Nullable<NativeModuleEnumDeclaration> {
|
|
if (!typeResolution.successful || typeResolution.type !== 'enum') {
|
|
throw new UnsupportedTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
parser.language(),
|
|
);
|
|
}
|
|
|
|
const enumName = typeResolution.name;
|
|
|
|
const enumMemberType = parser.parseEnumMembersType(typeAnnotation);
|
|
|
|
try {
|
|
parser.validateEnumMembersSupported(typeAnnotation, enumMemberType);
|
|
} catch (e) {
|
|
if (e instanceof Error) {
|
|
throw new ParserError(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
`Failed parsing the enum ${enumName} in ${hasteModuleName} with the error: ${e.message}`,
|
|
);
|
|
} else {
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
const enumMembers = parser.parseEnumMembers(typeAnnotation);
|
|
|
|
enumMap[enumName] = {
|
|
name: enumName,
|
|
type: 'EnumDeclarationWithMembers',
|
|
memberType: enumMemberType,
|
|
members: enumMembers,
|
|
};
|
|
|
|
return wrapNullable(nullable, {
|
|
name: enumName,
|
|
type: 'EnumDeclaration',
|
|
memberType: enumMemberType,
|
|
});
|
|
}
|
|
|
|
function emitPromise(
|
|
hasteModuleName: string,
|
|
typeAnnotation: $FlowFixMe,
|
|
parser: Parser,
|
|
nullable: boolean,
|
|
types: TypeDeclarationMap,
|
|
aliasMap: {...NativeModuleAliasMap},
|
|
enumMap: {...NativeModuleEnumMap},
|
|
tryParse: ParserErrorCapturer,
|
|
cxxOnly: boolean,
|
|
translateTypeAnnotation: $FlowFixMe,
|
|
): Nullable<NativeModulePromiseTypeAnnotation> {
|
|
assertGenericTypeAnnotationHasExactlyOneTypeParameter(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
|
|
const elementType = typeAnnotation.typeParameters.params[0];
|
|
if (
|
|
elementType.type === 'ExistsTypeAnnotation' ||
|
|
elementType.type === 'EmptyTypeAnnotation'
|
|
) {
|
|
return wrapNullable(nullable, {
|
|
type: 'PromiseTypeAnnotation',
|
|
elementType: {
|
|
type: 'VoidTypeAnnotation',
|
|
},
|
|
});
|
|
} else {
|
|
try {
|
|
return wrapNullable(nullable, {
|
|
type: 'PromiseTypeAnnotation',
|
|
elementType: translateTypeAnnotation(
|
|
hasteModuleName,
|
|
typeAnnotation.typeParameters.params[0],
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
parser,
|
|
),
|
|
});
|
|
} catch {
|
|
return wrapNullable(nullable, {
|
|
type: 'PromiseTypeAnnotation',
|
|
elementType: {
|
|
type: 'VoidTypeAnnotation',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function emitGenericObject(
|
|
nullable: boolean,
|
|
): Nullable<NativeModuleGenericObjectTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'GenericObjectTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitDictionary(
|
|
nullable: boolean,
|
|
valueType: Nullable<NativeModuleTypeAnnotation>,
|
|
): Nullable<NativeModuleGenericObjectTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'GenericObjectTypeAnnotation',
|
|
dictionaryValueType: valueType,
|
|
});
|
|
}
|
|
|
|
function emitObject(
|
|
nullable: boolean,
|
|
properties: Array<$FlowFixMe>,
|
|
): Nullable<NativeModuleObjectTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'ObjectTypeAnnotation',
|
|
properties,
|
|
});
|
|
}
|
|
|
|
function emitFloat(nullable: boolean): Nullable<FloatTypeAnnotation> {
|
|
return wrapNullable(nullable, {
|
|
type: 'FloatTypeAnnotation',
|
|
});
|
|
}
|
|
|
|
function emitFloatProp(
|
|
name: string,
|
|
optional: boolean,
|
|
): NamedShape<EventTypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'FloatTypeAnnotation',
|
|
},
|
|
};
|
|
}
|
|
|
|
function emitUnion(
|
|
nullable: boolean,
|
|
hasteModuleName: string,
|
|
typeAnnotation: $FlowFixMe,
|
|
parser: Parser,
|
|
): Nullable<
|
|
NativeModuleUnionTypeAnnotation | StringLiteralUnionTypeAnnotation,
|
|
> {
|
|
// Get all the literals by type
|
|
// Verify they are all the same
|
|
// If string, persist as StringLiteralUnionType
|
|
// If number, persist as NumberTypeAnnotation (TODO: Number literal)
|
|
|
|
const unionTypes = parser.remapUnionTypeAnnotationMemberNames(
|
|
typeAnnotation.types,
|
|
);
|
|
|
|
// Only support unionTypes of the same kind
|
|
if (unionTypes.length > 1) {
|
|
throw new UnsupportedUnionTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
unionTypes,
|
|
);
|
|
}
|
|
|
|
if (unionTypes[0] === 'StringTypeAnnotation') {
|
|
// Reprocess as a string literal union
|
|
return emitStringLiteralUnion(
|
|
nullable,
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
}
|
|
|
|
return wrapNullable(nullable, {
|
|
type: 'UnionTypeAnnotation',
|
|
memberType: unionTypes[0],
|
|
});
|
|
}
|
|
|
|
function emitStringLiteralUnion(
|
|
nullable: boolean,
|
|
hasteModuleName: string,
|
|
typeAnnotation: $FlowFixMe,
|
|
parser: Parser,
|
|
): Nullable<StringLiteralUnionTypeAnnotation> {
|
|
const stringLiterals =
|
|
parser.getStringLiteralUnionTypeAnnotationStringLiterals(
|
|
typeAnnotation.types,
|
|
);
|
|
|
|
return wrapNullable(nullable, {
|
|
type: 'StringLiteralUnionTypeAnnotation',
|
|
types: stringLiterals.map(stringLiteral => ({
|
|
type: 'StringLiteralTypeAnnotation',
|
|
value: stringLiteral,
|
|
})),
|
|
});
|
|
}
|
|
|
|
function translateArrayTypeAnnotation(
|
|
hasteModuleName: string,
|
|
types: TypeDeclarationMap,
|
|
aliasMap: {...NativeModuleAliasMap},
|
|
enumMap: {...NativeModuleEnumMap},
|
|
cxxOnly: boolean,
|
|
arrayType: 'Array' | 'ReadonlyArray',
|
|
elementType: $FlowFixMe,
|
|
nullable: boolean,
|
|
translateTypeAnnotation: $FlowFixMe,
|
|
parser: Parser,
|
|
): Nullable<NativeModuleTypeAnnotation> {
|
|
try {
|
|
/**
|
|
* TODO(T72031674): Migrate all our NativeModule specs to not use
|
|
* invalid Array ElementTypes. Then, make the elementType a required
|
|
* parameter.
|
|
*/
|
|
const [_elementType, isElementTypeNullable] = unwrapNullable<$FlowFixMe>(
|
|
translateTypeAnnotation(
|
|
hasteModuleName,
|
|
elementType,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
/**
|
|
* TODO(T72031674): Ensure that all ParsingErrors that are thrown
|
|
* while parsing the array element don't get captured and collected.
|
|
* Why? If we detect any parsing error while parsing the element,
|
|
* we should default it to null down the line, here. This is
|
|
* the correct behaviour until we migrate all our NativeModule specs
|
|
* to be parseable.
|
|
*/
|
|
nullGuard,
|
|
cxxOnly,
|
|
parser,
|
|
),
|
|
);
|
|
|
|
throwIfArrayElementTypeAnnotationIsUnsupported(
|
|
hasteModuleName,
|
|
elementType,
|
|
arrayType,
|
|
_elementType.type,
|
|
);
|
|
|
|
return wrapNullable(nullable, {
|
|
type: 'ArrayTypeAnnotation',
|
|
// $FlowFixMe[incompatible-call]
|
|
elementType: wrapNullable(isElementTypeNullable, _elementType),
|
|
});
|
|
} catch (ex) {
|
|
return wrapNullable(nullable, {
|
|
type: 'ArrayTypeAnnotation',
|
|
elementType: {
|
|
type: 'AnyTypeAnnotation',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
function emitArrayType(
|
|
hasteModuleName: string,
|
|
typeAnnotation: $FlowFixMe,
|
|
parser: Parser,
|
|
types: TypeDeclarationMap,
|
|
aliasMap: {...NativeModuleAliasMap},
|
|
enumMap: {...NativeModuleEnumMap},
|
|
cxxOnly: boolean,
|
|
nullable: boolean,
|
|
translateTypeAnnotation: $FlowFixMe,
|
|
): Nullable<NativeModuleTypeAnnotation> {
|
|
assertGenericTypeAnnotationHasExactlyOneTypeParameter(
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
parser,
|
|
);
|
|
|
|
return translateArrayTypeAnnotation(
|
|
hasteModuleName,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
cxxOnly,
|
|
typeAnnotation.type,
|
|
typeAnnotation.typeParameters.params[0],
|
|
nullable,
|
|
translateTypeAnnotation,
|
|
parser,
|
|
);
|
|
}
|
|
|
|
function Visitor(infoMap: {isComponent: boolean, isModule: boolean}): {
|
|
[type: string]: (node: $FlowFixMe) => void,
|
|
} {
|
|
return {
|
|
CallExpression(node: $FlowFixMe) {
|
|
if (
|
|
node.callee.type === 'Identifier' &&
|
|
node.callee.name === 'codegenNativeComponent'
|
|
) {
|
|
infoMap.isComponent = true;
|
|
}
|
|
|
|
if (isModuleRegistryCall(node)) {
|
|
infoMap.isModule = true;
|
|
}
|
|
},
|
|
InterfaceExtends(node: $FlowFixMe) {
|
|
if (node.id.name === 'TurboModule') {
|
|
infoMap.isModule = true;
|
|
}
|
|
},
|
|
TSInterfaceDeclaration(node: $FlowFixMe) {
|
|
if (
|
|
Array.isArray(node.extends) &&
|
|
node.extends.some(
|
|
extension => extension.expression.name === 'TurboModule',
|
|
)
|
|
) {
|
|
infoMap.isModule = true;
|
|
}
|
|
},
|
|
};
|
|
}
|
|
|
|
function emitPartial(
|
|
nullable: boolean,
|
|
hasteModuleName: string,
|
|
typeAnnotation: $FlowFixMe,
|
|
types: TypeDeclarationMap,
|
|
aliasMap: {...NativeModuleAliasMap},
|
|
enumMap: {...NativeModuleEnumMap},
|
|
tryParse: ParserErrorCapturer,
|
|
cxxOnly: boolean,
|
|
parser: Parser,
|
|
): Nullable<NativeModuleTypeAnnotation> {
|
|
throwIfPartialWithMoreParameter(typeAnnotation);
|
|
|
|
throwIfPartialNotAnnotatingTypeParameter(typeAnnotation, types, parser);
|
|
|
|
const annotatedElement = parser.extractAnnotatedElement(
|
|
typeAnnotation,
|
|
types,
|
|
);
|
|
const annotatedElementProperties =
|
|
parser.getAnnotatedElementProperties(annotatedElement);
|
|
|
|
const partialProperties = parser.computePartialProperties(
|
|
annotatedElementProperties,
|
|
hasteModuleName,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
);
|
|
|
|
return emitObject(nullable, partialProperties);
|
|
}
|
|
|
|
function emitCommonTypes(
|
|
hasteModuleName: string,
|
|
types: TypeDeclarationMap,
|
|
typeAnnotation: $FlowFixMe,
|
|
aliasMap: {...NativeModuleAliasMap},
|
|
enumMap: {...NativeModuleEnumMap},
|
|
tryParse: ParserErrorCapturer,
|
|
cxxOnly: boolean,
|
|
nullable: boolean,
|
|
parser: Parser,
|
|
): $FlowFixMe {
|
|
const typeMap = {
|
|
Stringish: emitStringish,
|
|
Int32: emitInt32,
|
|
Double: emitDouble,
|
|
Float: emitFloat,
|
|
UnsafeObject: emitGenericObject,
|
|
Object: emitGenericObject,
|
|
$Partial: emitPartial,
|
|
Partial: emitPartial,
|
|
BooleanTypeAnnotation: emitBoolean,
|
|
NumberTypeAnnotation: emitNumber,
|
|
VoidTypeAnnotation: emitVoid,
|
|
StringTypeAnnotation: emitString,
|
|
MixedTypeAnnotation: cxxOnly ? emitMixed : emitGenericObject,
|
|
};
|
|
|
|
const typeAnnotationName = parser.convertKeywordToTypeAnnotation(
|
|
typeAnnotation.type,
|
|
);
|
|
|
|
// $FlowFixMe[invalid-computed-prop]
|
|
const simpleEmitter = typeMap[typeAnnotationName];
|
|
if (simpleEmitter) {
|
|
return simpleEmitter(nullable);
|
|
}
|
|
|
|
const genericTypeAnnotationName =
|
|
parser.getTypeAnnotationName(typeAnnotation);
|
|
|
|
// $FlowFixMe[invalid-computed-prop]
|
|
const emitter = typeMap[genericTypeAnnotationName];
|
|
if (!emitter) {
|
|
return null;
|
|
}
|
|
|
|
return emitter(
|
|
nullable,
|
|
hasteModuleName,
|
|
typeAnnotation,
|
|
types,
|
|
aliasMap,
|
|
enumMap,
|
|
tryParse,
|
|
cxxOnly,
|
|
parser,
|
|
);
|
|
}
|
|
|
|
function emitBoolProp(
|
|
name: string,
|
|
optional: boolean,
|
|
): NamedShape<EventTypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'BooleanTypeAnnotation',
|
|
},
|
|
};
|
|
}
|
|
|
|
function emitMixedProp(
|
|
name: string,
|
|
optional: boolean,
|
|
): NamedShape<EventTypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'MixedTypeAnnotation',
|
|
},
|
|
};
|
|
}
|
|
|
|
function emitObjectProp(
|
|
name: string,
|
|
optional: boolean,
|
|
parser: Parser,
|
|
typeAnnotation: $FlowFixMe,
|
|
extractArrayElementType: (
|
|
typeAnnotation: $FlowFixMe,
|
|
name: string,
|
|
parser: Parser,
|
|
) => EventTypeAnnotation,
|
|
): NamedShape<EventTypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: extractArrayElementType(typeAnnotation, name, parser),
|
|
};
|
|
}
|
|
|
|
function emitUnionProp(
|
|
name: string,
|
|
optional: boolean,
|
|
parser: Parser,
|
|
typeAnnotation: $FlowFixMe,
|
|
): NamedShape<EventTypeAnnotation> {
|
|
return {
|
|
name,
|
|
optional,
|
|
typeAnnotation: {
|
|
type: 'StringEnumTypeAnnotation',
|
|
options: typeAnnotation.types.map(option =>
|
|
parser.getLiteralValue(option),
|
|
),
|
|
},
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
emitArrayType,
|
|
emitBoolean,
|
|
emitBoolProp,
|
|
emitDouble,
|
|
emitDoubleProp,
|
|
emitFloat,
|
|
emitFloatProp,
|
|
emitFunction,
|
|
emitInt32,
|
|
emitInt32Prop,
|
|
emitMixedProp,
|
|
emitNumber,
|
|
emitNumberLiteral,
|
|
emitGenericObject,
|
|
emitDictionary,
|
|
emitObject,
|
|
emitPromise,
|
|
emitRootTag,
|
|
emitVoid,
|
|
emitString,
|
|
emitStringish,
|
|
emitStringProp,
|
|
emitStringLiteral,
|
|
emitMixed,
|
|
emitUnion,
|
|
emitPartial,
|
|
emitCommonTypes,
|
|
typeAliasResolution,
|
|
typeEnumResolution,
|
|
translateArrayTypeAnnotation,
|
|
Visitor,
|
|
emitObjectProp,
|
|
emitUnionProp,
|
|
};
|