320 lines
8.3 KiB
Plaintext
320 lines
8.3 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 {NativeModuleTypeAnnotation} from '../CodegenSchema';
|
|
import type {ParserType} from './errors';
|
|
import type {Parser} from './parser';
|
|
import type {TypeDeclarationMap} from '../parsers/utils';
|
|
|
|
const {
|
|
MisnamedModuleInterfaceParserError,
|
|
UnsupportedFunctionReturnTypeAnnotationParserError,
|
|
ModuleInterfaceNotFoundParserError,
|
|
MoreThanOneModuleRegistryCallsParserError,
|
|
UnusedModuleInterfaceParserError,
|
|
IncorrectModuleRegistryCallArityParserError,
|
|
IncorrectModuleRegistryCallTypeParameterParserError,
|
|
IncorrectModuleRegistryCallArgumentTypeParserError,
|
|
UnsupportedObjectPropertyValueTypeAnnotationParserError,
|
|
UntypedModuleRegistryCallParserError,
|
|
UnsupportedModulePropertyParserError,
|
|
MoreThanOneModuleInterfaceParserError,
|
|
UnsupportedFunctionParamTypeAnnotationParserError,
|
|
UnsupportedArrayElementTypeAnnotationParserError,
|
|
} = require('./errors');
|
|
|
|
function throwIfModuleInterfaceIsMisnamed(
|
|
nativeModuleName: string,
|
|
moduleSpecId: $FlowFixMe,
|
|
parserType: ParserType,
|
|
) {
|
|
if (moduleSpecId.name !== 'Spec') {
|
|
throw new MisnamedModuleInterfaceParserError(
|
|
nativeModuleName,
|
|
moduleSpecId,
|
|
parserType,
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfModuleInterfaceNotFound(
|
|
numberOfModuleSpecs: number,
|
|
nativeModuleName: string,
|
|
ast: $FlowFixMe,
|
|
parserType: ParserType,
|
|
) {
|
|
if (numberOfModuleSpecs === 0) {
|
|
throw new ModuleInterfaceNotFoundParserError(
|
|
nativeModuleName,
|
|
ast,
|
|
parserType,
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfMoreThanOneModuleRegistryCalls(
|
|
hasteModuleName: string,
|
|
callExpressions: $FlowFixMe,
|
|
callExpressionsLength: number,
|
|
) {
|
|
if (callExpressions.length > 1) {
|
|
throw new MoreThanOneModuleRegistryCallsParserError(
|
|
hasteModuleName,
|
|
callExpressions,
|
|
callExpressionsLength,
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfUnusedModuleInterfaceParserError(
|
|
nativeModuleName: string,
|
|
moduleSpec: $FlowFixMe,
|
|
callExpressions: $FlowFixMe,
|
|
) {
|
|
if (callExpressions.length === 0) {
|
|
throw new UnusedModuleInterfaceParserError(nativeModuleName, moduleSpec);
|
|
}
|
|
}
|
|
|
|
function throwIfWrongNumberOfCallExpressionArgs(
|
|
nativeModuleName: string,
|
|
flowCallExpression: $FlowFixMe,
|
|
methodName: string,
|
|
numberOfCallExpressionArgs: number,
|
|
) {
|
|
if (numberOfCallExpressionArgs !== 1) {
|
|
throw new IncorrectModuleRegistryCallArityParserError(
|
|
nativeModuleName,
|
|
flowCallExpression,
|
|
methodName,
|
|
numberOfCallExpressionArgs,
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfIncorrectModuleRegistryCallTypeParameterParserError(
|
|
nativeModuleName: string,
|
|
typeArguments: $FlowFixMe,
|
|
methodName: string,
|
|
moduleName: string,
|
|
parser: Parser,
|
|
) {
|
|
function throwError() {
|
|
throw new IncorrectModuleRegistryCallTypeParameterParserError(
|
|
nativeModuleName,
|
|
typeArguments,
|
|
methodName,
|
|
moduleName,
|
|
);
|
|
}
|
|
|
|
if (parser.checkIfInvalidModule(typeArguments)) {
|
|
throwError();
|
|
}
|
|
}
|
|
|
|
function throwIfUnsupportedFunctionReturnTypeAnnotationParserError(
|
|
nativeModuleName: string,
|
|
returnTypeAnnotation: $FlowFixMe,
|
|
invalidReturnType: string,
|
|
cxxOnly: boolean,
|
|
returnType: string,
|
|
) {
|
|
if (!cxxOnly && returnType === 'FunctionTypeAnnotation') {
|
|
throw new UnsupportedFunctionReturnTypeAnnotationParserError(
|
|
nativeModuleName,
|
|
returnTypeAnnotation.returnType,
|
|
'FunctionTypeAnnotation',
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfUntypedModule(
|
|
typeArguments: $FlowFixMe,
|
|
hasteModuleName: string,
|
|
callExpression: $FlowFixMe,
|
|
methodName: string,
|
|
moduleName: string,
|
|
) {
|
|
if (typeArguments == null) {
|
|
throw new UntypedModuleRegistryCallParserError(
|
|
hasteModuleName,
|
|
callExpression,
|
|
methodName,
|
|
moduleName,
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfModuleTypeIsUnsupported(
|
|
nativeModuleName: string,
|
|
propertyValue: $FlowFixMe,
|
|
propertyName: string,
|
|
propertyValueType: string,
|
|
parser: Parser,
|
|
) {
|
|
if (!parser.functionTypeAnnotation(propertyValueType)) {
|
|
throw new UnsupportedModulePropertyParserError(
|
|
nativeModuleName,
|
|
propertyValue,
|
|
propertyName,
|
|
propertyValueType,
|
|
parser.language(),
|
|
);
|
|
}
|
|
}
|
|
|
|
const UnsupportedObjectPropertyTypeToInvalidPropertyValueTypeMap = {
|
|
FunctionTypeAnnotation: 'FunctionTypeAnnotation',
|
|
VoidTypeAnnotation: 'void',
|
|
PromiseTypeAnnotation: 'Promise',
|
|
};
|
|
|
|
function throwIfPropertyValueTypeIsUnsupported(
|
|
moduleName: string,
|
|
propertyValue: $FlowFixMe,
|
|
propertyKey: string,
|
|
type: string,
|
|
) {
|
|
const invalidPropertyValueType =
|
|
UnsupportedObjectPropertyTypeToInvalidPropertyValueTypeMap[type];
|
|
|
|
throw new UnsupportedObjectPropertyValueTypeAnnotationParserError(
|
|
moduleName,
|
|
propertyValue,
|
|
propertyKey,
|
|
invalidPropertyValueType,
|
|
);
|
|
}
|
|
|
|
function throwIfMoreThanOneModuleInterfaceParserError(
|
|
nativeModuleName: string,
|
|
moduleSpecs: $ReadOnlyArray<$FlowFixMe>,
|
|
parserType: ParserType,
|
|
) {
|
|
if (moduleSpecs.length > 1) {
|
|
throw new MoreThanOneModuleInterfaceParserError(
|
|
nativeModuleName,
|
|
moduleSpecs,
|
|
moduleSpecs.map(node => node.id.name),
|
|
parserType,
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfUnsupportedFunctionParamTypeAnnotationParserError(
|
|
nativeModuleName: string,
|
|
languageParamTypeAnnotation: $FlowFixMe,
|
|
paramName: string,
|
|
paramTypeAnnotationType: NativeModuleTypeAnnotation['type'],
|
|
) {
|
|
throw new UnsupportedFunctionParamTypeAnnotationParserError(
|
|
nativeModuleName,
|
|
languageParamTypeAnnotation,
|
|
paramName,
|
|
paramTypeAnnotationType,
|
|
);
|
|
}
|
|
|
|
function throwIfArrayElementTypeAnnotationIsUnsupported(
|
|
hasteModuleName: string,
|
|
flowElementType: $FlowFixMe,
|
|
flowArrayType: 'Array' | '$ReadOnlyArray' | 'ReadonlyArray',
|
|
type: string,
|
|
) {
|
|
const TypeMap = {
|
|
FunctionTypeAnnotation: 'FunctionTypeAnnotation',
|
|
VoidTypeAnnotation: 'void',
|
|
PromiseTypeAnnotation: 'Promise',
|
|
// TODO: Added as a work-around for now until TupleTypeAnnotation are fully supported in both flow and TS
|
|
// Right now they are partially treated as UnionTypeAnnotation
|
|
UnionTypeAnnotation: 'UnionTypeAnnotation',
|
|
};
|
|
|
|
if (type in TypeMap) {
|
|
throw new UnsupportedArrayElementTypeAnnotationParserError(
|
|
hasteModuleName,
|
|
flowElementType,
|
|
flowArrayType,
|
|
TypeMap[type],
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfIncorrectModuleRegistryCallArgument(
|
|
nativeModuleName: string,
|
|
callExpressionArg: $FlowFixMe,
|
|
methodName: string,
|
|
) {
|
|
if (
|
|
callExpressionArg.type !== 'StringLiteral' &&
|
|
callExpressionArg.type !== 'Literal'
|
|
) {
|
|
const {type} = callExpressionArg;
|
|
throw new IncorrectModuleRegistryCallArgumentTypeParserError(
|
|
nativeModuleName,
|
|
callExpressionArg,
|
|
methodName,
|
|
type,
|
|
);
|
|
}
|
|
}
|
|
|
|
function throwIfPartialNotAnnotatingTypeParameter(
|
|
typeAnnotation: $FlowFixMe,
|
|
types: TypeDeclarationMap,
|
|
parser: Parser,
|
|
) {
|
|
const annotatedElement = parser.extractAnnotatedElement(
|
|
typeAnnotation,
|
|
types,
|
|
);
|
|
|
|
if (!annotatedElement) {
|
|
throw new Error('Partials only support annotating a type parameter.');
|
|
}
|
|
}
|
|
|
|
function throwIfPartialWithMoreParameter(typeAnnotation: $FlowFixMe) {
|
|
if (typeAnnotation.typeParameters.params.length !== 1) {
|
|
throw new Error('Partials only support annotating exactly one parameter.');
|
|
}
|
|
}
|
|
|
|
function throwIfMoreThanOneCodegenNativecommands(
|
|
commandsTypeNames: $ReadOnlyArray<$FlowFixMe>,
|
|
) {
|
|
if (commandsTypeNames.length > 1) {
|
|
throw new Error('codegenNativeCommands may only be called once in a file');
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
throwIfModuleInterfaceIsMisnamed,
|
|
throwIfUnsupportedFunctionReturnTypeAnnotationParserError,
|
|
throwIfModuleInterfaceNotFound,
|
|
throwIfMoreThanOneModuleRegistryCalls,
|
|
throwIfPropertyValueTypeIsUnsupported,
|
|
throwIfUnusedModuleInterfaceParserError,
|
|
throwIfWrongNumberOfCallExpressionArgs,
|
|
throwIfIncorrectModuleRegistryCallTypeParameterParserError,
|
|
throwIfUntypedModule,
|
|
throwIfModuleTypeIsUnsupported,
|
|
throwIfMoreThanOneModuleInterfaceParserError,
|
|
throwIfUnsupportedFunctionParamTypeAnnotationParserError,
|
|
throwIfArrayElementTypeAnnotationIsUnsupported,
|
|
throwIfIncorrectModuleRegistryCallArgument,
|
|
throwIfPartialNotAnnotatingTypeParameter,
|
|
throwIfPartialWithMoreParameter,
|
|
throwIfMoreThanOneCodegenNativecommands,
|
|
};
|