/** * 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 {UnionTypeAnnotationMemberType} from '../CodegenSchema'; import type {Parser} from './parser'; export type ParserType = 'Flow' | 'TypeScript'; class ParserError extends Error { nodes: $ReadOnlyArray<$FlowFixMe>; constructor( nativeModuleName: string, astNodeOrNodes: $FlowFixMe, message: string, ) { super(`Module ${nativeModuleName}: ${message}`); this.nodes = Array.isArray(astNodeOrNodes) ? astNodeOrNodes : [astNodeOrNodes]; // assign the error class name in your custom error (as a shortcut) this.name = this.constructor.name; // capturing the stack trace keeps the reference to your error class Error.captureStackTrace(this, this.constructor); } } class MisnamedModuleInterfaceParserError extends ParserError { constructor(nativeModuleName: string, id: $FlowFixMe, language: ParserType) { super( nativeModuleName, id, `All ${language} interfaces extending TurboModule must be called 'Spec'. Please rename ${language} interface '${id.name}' to 'Spec'.`, ); } } class ModuleInterfaceNotFoundParserError extends ParserError { constructor(nativeModuleName: string, ast: $FlowFixMe, language: ParserType) { super( nativeModuleName, ast, `No ${language} interfaces extending TurboModule were detected in this NativeModule spec.`, ); } } class MoreThanOneModuleInterfaceParserError extends ParserError { constructor( nativeModuleName: string, flowModuleInterfaces: $ReadOnlyArray<$FlowFixMe>, names: $ReadOnlyArray, language: ParserType, ) { const finalName = names[names.length - 1]; const allButLastName = names.slice(0, -1); const quote = (x: string) => `'${x}'`; const nameStr = allButLastName.map(quote).join(', ') + ', and ' + quote(finalName); super( nativeModuleName, flowModuleInterfaces, `Every NativeModule spec file must declare exactly one NativeModule ${language} interface. This file declares ${names.length}: ${nameStr}. Please remove the extraneous ${language} interface declarations.`, ); } } class UnsupportedModulePropertyParserError extends ParserError { constructor( nativeModuleName: string, propertyValue: $FlowFixMe, propertyName: string, invalidPropertyValueType: string, language: ParserType, ) { super( nativeModuleName, propertyValue, `${language} interfaces extending TurboModule must only contain 'FunctionTypeAnnotation's. Property '${propertyName}' refers to a '${invalidPropertyValueType}'.`, ); } } class UnsupportedTypeAnnotationParserError extends ParserError { +typeAnnotationType: string; constructor( nativeModuleName: string, typeAnnotation: $FlowFixMe, language: ParserType, ) { super( nativeModuleName, typeAnnotation, `${language} type annotation '${typeAnnotation.type}' is unsupported in NativeModule specs.`, ); this.typeAnnotationType = typeAnnotation.type; } } class UnsupportedGenericParserError extends ParserError { // +genericName: string; constructor( nativeModuleName: string, genericTypeAnnotation: $FlowFixMe, parser: Parser, ) { const genericName = parser.nameForGenericTypeAnnotation( genericTypeAnnotation, ); super( nativeModuleName, genericTypeAnnotation, `Unrecognized generic type '${genericName}' in NativeModule spec.`, ); // this.genericName = genericName; } } class MissingTypeParameterGenericParserError extends ParserError { constructor( nativeModuleName: string, genericTypeAnnotation: $FlowFixMe, parser: Parser, ) { const genericName = parser.nameForGenericTypeAnnotation( genericTypeAnnotation, ); super( nativeModuleName, genericTypeAnnotation, `Generic '${genericName}' must have type parameters.`, ); } } class MoreThanOneTypeParameterGenericParserError extends ParserError { constructor( nativeModuleName: string, genericTypeAnnotation: $FlowFixMe, parser: Parser, ) { const genericName = parser.nameForGenericTypeAnnotation( genericTypeAnnotation, ); super( nativeModuleName, genericTypeAnnotation, `Generic '${genericName}' must have exactly one type parameter.`, ); } } /** * Array parsing errors */ class UnsupportedArrayElementTypeAnnotationParserError extends ParserError { constructor( nativeModuleName: string, arrayElementTypeAST: $FlowFixMe, arrayType: 'Array' | '$ReadOnlyArray' | 'ReadonlyArray', invalidArrayElementType: string, ) { super( nativeModuleName, arrayElementTypeAST, `${arrayType} element types cannot be '${invalidArrayElementType}'.`, ); } } /** * Object parsing errors */ class UnsupportedObjectPropertyTypeAnnotationParserError extends ParserError { constructor( nativeModuleName: string, propertyAST: $FlowFixMe, invalidPropertyType: string, language: ParserType, ) { let message = `'ObjectTypeAnnotation' cannot contain '${invalidPropertyType}'.`; if ( invalidPropertyType === 'ObjectTypeSpreadProperty' && language !== 'TypeScript' ) { message = "Object spread isn't supported in 'ObjectTypeAnnotation's."; } super(nativeModuleName, propertyAST, message); } } class UnsupportedObjectPropertyValueTypeAnnotationParserError extends ParserError { constructor( nativeModuleName: string, propertyValueAST: $FlowFixMe, propertyName: string, invalidPropertyValueType: string, ) { super( nativeModuleName, propertyValueAST, `Object property '${propertyName}' cannot have type '${invalidPropertyValueType}'.`, ); } } /** * Function parsing errors */ class UnnamedFunctionParamParserError extends ParserError { constructor(functionParam: $FlowFixMe, nativeModuleName: string) { super( nativeModuleName, functionParam, 'All function parameters must be named.', ); } } class UnsupportedFunctionParamTypeAnnotationParserError extends ParserError { constructor( nativeModuleName: string, flowParamTypeAnnotation: $FlowFixMe, paramName: string, invalidParamType: string, ) { super( nativeModuleName, flowParamTypeAnnotation, `Function parameter '${paramName}' cannot have type '${invalidParamType}'.`, ); } } class UnsupportedFunctionReturnTypeAnnotationParserError extends ParserError { constructor( nativeModuleName: string, flowReturnTypeAnnotation: $FlowFixMe, invalidReturnType: string, ) { super( nativeModuleName, flowReturnTypeAnnotation, `Function return cannot have type '${invalidReturnType}'.`, ); } } /** * Enum parsing errors */ class UnsupportedEnumDeclarationParserError extends ParserError { constructor( nativeModuleName: string, arrayElementTypeAST: $FlowFixMe, memberType: string, ) { super( nativeModuleName, arrayElementTypeAST, `Unexpected enum member type ${memberType}. Only string and number enum members are supported`, ); } } /** * Union parsing errors */ class UnsupportedUnionTypeAnnotationParserError extends ParserError { constructor( nativeModuleName: string, arrayElementTypeAST: $FlowFixMe, types: UnionTypeAnnotationMemberType[], ) { super( nativeModuleName, arrayElementTypeAST, `Union members must be of the same type, but multiple types were found ${types.join( ', ', )}'.`, ); } } /** * Module parsing errors */ class UnusedModuleInterfaceParserError extends ParserError { constructor(nativeModuleName: string, flowInterface: $FlowFixMe) { super( nativeModuleName, flowInterface, "Unused NativeModule spec. Please load the NativeModule by calling TurboModuleRegistry.get('').", ); } } class MoreThanOneModuleRegistryCallsParserError extends ParserError { constructor( nativeModuleName: string, flowCallExpressions: $FlowFixMe, numCalls: number, ) { super( nativeModuleName, flowCallExpressions, `Every NativeModule spec file must contain exactly one NativeModule load. This file contains ${numCalls}. Please simplify this spec file, splitting it as necessary, to remove the extraneous loads.`, ); } } class UntypedModuleRegistryCallParserError extends ParserError { constructor( nativeModuleName: string, flowCallExpression: $FlowFixMe, methodName: string, moduleName: string, ) { super( nativeModuleName, flowCallExpression, `Please type this NativeModule load: TurboModuleRegistry.${methodName}('${moduleName}').`, ); } } class IncorrectModuleRegistryCallTypeParameterParserError extends ParserError { constructor( nativeModuleName: string, flowTypeArguments: $FlowFixMe, methodName: string, moduleName: string, ) { super( nativeModuleName, flowTypeArguments, `Please change these type arguments to reflect TurboModuleRegistry.${methodName}('${moduleName}').`, ); } } class IncorrectModuleRegistryCallArityParserError extends ParserError { constructor( nativeModuleName: string, flowCallExpression: $FlowFixMe, methodName: string, incorrectArity: number, ) { super( nativeModuleName, flowCallExpression, `Please call TurboModuleRegistry.${methodName}() with exactly one argument. Detected ${incorrectArity}.`, ); } } class IncorrectModuleRegistryCallArgumentTypeParserError extends ParserError { constructor( nativeModuleName: string, flowArgument: $FlowFixMe, methodName: string, type: string, ) { const a = /[aeiouy]/.test(type.toLowerCase()) ? 'an' : 'a'; super( nativeModuleName, flowArgument, `Please call TurboModuleRegistry.${methodName}() with a string literal. Detected ${a} '${type}'`, ); } } module.exports = { ParserError, MissingTypeParameterGenericParserError, MoreThanOneTypeParameterGenericParserError, MisnamedModuleInterfaceParserError, ModuleInterfaceNotFoundParserError, MoreThanOneModuleInterfaceParserError, UnnamedFunctionParamParserError, UnsupportedArrayElementTypeAnnotationParserError, UnsupportedGenericParserError, UnsupportedTypeAnnotationParserError, UnsupportedFunctionParamTypeAnnotationParserError, UnsupportedFunctionReturnTypeAnnotationParserError, UnsupportedEnumDeclarationParserError, UnsupportedUnionTypeAnnotationParserError, UnsupportedModulePropertyParserError, UnsupportedObjectPropertyTypeAnnotationParserError, UnsupportedObjectPropertyValueTypeAnnotationParserError, UnusedModuleInterfaceParserError, MoreThanOneModuleRegistryCallsParserError, UntypedModuleRegistryCallParserError, IncorrectModuleRegistryCallTypeParameterParserError, IncorrectModuleRegistryCallArityParserError, IncorrectModuleRegistryCallArgumentTypeParserError, };