// @flow
import * as t from '@babel/types';

export type VisitorFunc<N, S> = (
  N,
  S,
  Array<t.Node>,
) =>
  | void
  | t.Node
  | Array<t.Node>
  | symbol
  | (() => void | t.Node | Array<t.Node> | symbol);
type SingleVisitor<N, S> =
  | VisitorFunc<N, S>
  | {|
      enter?: VisitorFunc<N, S>,
      exit?: VisitorFunc<N, S>,
    |};

export type Visitors<S> = {
  shouldSkip?: t.Node => boolean,
  ReferencedIdentifier?: SingleVisitor<t.Identifier, S>,
  Function?: SingleVisitor<t.Function, S>,
  Class?: SingleVisitor<t.Class, S>,
  ArrayExpression?: SingleVisitor<t.ArrayExpression, S>,
  AssignmentExpression?: SingleVisitor<t.AssignmentExpression, S>,
  BinaryExpression?: SingleVisitor<t.BinaryExpression, S>,
  InterpreterDirective?: SingleVisitor<t.InterpreterDirective, S>,
  Directive?: SingleVisitor<t.Directive, S>,
  DirectiveLiteral?: SingleVisitor<t.DirectiveLiteral, S>,
  BlockStatement?: SingleVisitor<t.BlockStatement, S>,
  BreakStatement?: SingleVisitor<t.BreakStatement, S>,
  CallExpression?: SingleVisitor<t.CallExpression, S>,
  CatchClause?: SingleVisitor<t.CatchClause, S>,
  ConditionalExpression?: SingleVisitor<t.ConditionalExpression, S>,
  ContinueStatement?: SingleVisitor<t.ContinueStatement, S>,
  DebuggerStatement?: SingleVisitor<t.DebuggerStatement, S>,
  DoWhileStatement?: SingleVisitor<t.DoWhileStatement, S>,
  EmptyStatement?: SingleVisitor<t.EmptyStatement, S>,
  ExpressionStatement?: SingleVisitor<t.ExpressionStatement, S>,
  File?: SingleVisitor<t.File, S>,
  ForInStatement?: SingleVisitor<t.ForInStatement, S>,
  ForStatement?: SingleVisitor<t.ForStatement, S>,
  FunctionDeclaration?: SingleVisitor<t.FunctionDeclaration, S>,
  FunctionExpression?: SingleVisitor<t.FunctionExpression, S>,
  Identifier?: SingleVisitor<t.Identifier, S>,
  IfStatement?: SingleVisitor<t.IfStatement, S>,
  LabeledStatement?: SingleVisitor<t.LabeledStatement, S>,
  StringLiteral?: SingleVisitor<t.StringLiteral, S>,
  NumericLiteral?: SingleVisitor<t.NumericLiteral, S>,
  NullLiteral?: SingleVisitor<t.NullLiteral, S>,
  BooleanLiteral?: SingleVisitor<t.BooleanLiteral, S>,
  RegExpLiteral?: SingleVisitor<t.RegExpLiteral, S>,
  LogicalExpression?: SingleVisitor<t.LogicalExpression, S>,
  MemberExpression?: SingleVisitor<t.MemberExpression, S>,
  NewExpression?: SingleVisitor<t.NewExpression, S>,
  Program?: SingleVisitor<t.Program, S>,
  ObjectExpression?: SingleVisitor<t.ObjectExpression, S>,
  ObjectMethod?: SingleVisitor<t.ObjectMethod, S>,
  ObjectProperty?: SingleVisitor<t.ObjectProperty, S>,
  RestElement?: SingleVisitor<t.RestElement, S>,
  ReturnStatement?: SingleVisitor<t.ReturnStatement, S>,
  SequenceExpression?: SingleVisitor<t.SequenceExpression, S>,
  ParenthesizedExpression?: SingleVisitor<t.ParenthesizedExpression, S>,
  SwitchCase?: SingleVisitor<t.SwitchCase, S>,
  SwitchStatement?: SingleVisitor<t.SwitchStatement, S>,
  ThisExpression?: SingleVisitor<t.ThisExpression, S>,
  ThrowStatement?: SingleVisitor<t.ThrowStatement, S>,
  TryStatement?: SingleVisitor<t.TryStatement, S>,
  UnaryExpression?: SingleVisitor<t.UnaryExpression, S>,
  UpdateExpression?: SingleVisitor<t.UpdateExpression, S>,
  VariableDeclaration?: SingleVisitor<t.VariableDeclaration, S>,
  VariableDeclarator?: SingleVisitor<t.VariableDeclarator, S>,
  WhileStatement?: SingleVisitor<t.WhileStatement, S>,
  WithStatement?: SingleVisitor<t.WithStatement, S>,
  AssignmentPattern?: SingleVisitor<t.AssignmentPattern, S>,
  ArrayPattern?: SingleVisitor<t.ArrayPattern, S>,
  ArrowFunctionExpression?: SingleVisitor<t.ArrowFunctionExpression, S>,
  ClassBody?: SingleVisitor<t.ClassBody, S>,
  ClassExpression?: SingleVisitor<t.ClassExpression, S>,
  ClassDeclaration?: SingleVisitor<t.ClassDeclaration, S>,
  ExportAllDeclaration?: SingleVisitor<t.ExportAllDeclaration, S>,
  ExportDefaultDeclaration?: SingleVisitor<t.ExportDefaultDeclaration, S>,
  ExportNamedDeclaration?: SingleVisitor<t.ExportNamedDeclaration, S>,
  ExportSpecifier?: SingleVisitor<t.ExportSpecifier, S>,
  ForOfStatement?: SingleVisitor<t.ForOfStatement, S>,
  ImportDeclaration?: SingleVisitor<t.ImportDeclaration, S>,
  ImportDefaultSpecifier?: SingleVisitor<t.ImportDefaultSpecifier, S>,
  ImportNamespaceSpecifier?: SingleVisitor<t.ImportNamespaceSpecifier, S>,
  ImportSpecifier?: SingleVisitor<t.ImportSpecifier, S>,
  MetaProperty?: SingleVisitor<t.MetaProperty, S>,
  ClassMethod?: SingleVisitor<t.ClassMethod, S>,
  ObjectPattern?: SingleVisitor<t.ObjectPattern, S>,
  SpreadElement?: SingleVisitor<t.SpreadElement, S>,
  Super?: SingleVisitor<t.Super, S>,
  TaggedTemplateExpression?: SingleVisitor<t.TaggedTemplateExpression, S>,
  TemplateElement?: SingleVisitor<t.TemplateElement, S>,
  TemplateLiteral?: SingleVisitor<t.TemplateLiteral, S>,
  YieldExpression?: SingleVisitor<t.YieldExpression, S>,
  AnyTypeAnnotation?: SingleVisitor<t.AnyTypeAnnotation, S>,
  ArrayTypeAnnotation?: SingleVisitor<t.ArrayTypeAnnotation, S>,
  BooleanTypeAnnotation?: SingleVisitor<t.BooleanTypeAnnotation, S>,
  BooleanLiteralTypeAnnotation?: SingleVisitor<
    t.BooleanLiteralTypeAnnotation,
    S,
  >,
  NullLiteralTypeAnnotation?: SingleVisitor<t.NullLiteralTypeAnnotation, S>,
  ClassImplements?: SingleVisitor<t.ClassImplements, S>,
  DeclareClass?: SingleVisitor<t.DeclareClass, S>,
  DeclareFunction?: SingleVisitor<t.DeclareFunction, S>,
  DeclareInterface?: SingleVisitor<t.DeclareInterface, S>,
  DeclareModule?: SingleVisitor<t.DeclareModule, S>,
  DeclareModuleExports?: SingleVisitor<t.DeclareModuleExports, S>,
  DeclareTypeAlias?: SingleVisitor<t.DeclareTypeAlias, S>,
  DeclareOpaqueType?: SingleVisitor<t.DeclareOpaqueType, S>,
  DeclareVariable?: SingleVisitor<t.DeclareVariable, S>,
  DeclareExportDeclaration?: SingleVisitor<t.DeclareExportDeclaration, S>,
  DeclareExportAllDeclaration?: SingleVisitor<t.DeclareExportAllDeclaration, S>,
  DeclaredPredicate?: SingleVisitor<t.DeclaredPredicate, S>,
  ExistsTypeAnnotation?: SingleVisitor<t.ExistsTypeAnnotation, S>,
  FunctionTypeAnnotation?: SingleVisitor<t.FunctionTypeAnnotation, S>,
  FunctionTypeParam?: SingleVisitor<t.FunctionTypeParam, S>,
  GenericTypeAnnotation?: SingleVisitor<t.GenericTypeAnnotation, S>,
  InferredPredicate?: SingleVisitor<t.InferredPredicate, S>,
  InterfaceExtends?: SingleVisitor<t.InterfaceExtends, S>,
  InterfaceDeclaration?: SingleVisitor<t.InterfaceDeclaration, S>,
  InterfaceTypeAnnotation?: SingleVisitor<t.InterfaceTypeAnnotation, S>,
  IntersectionTypeAnnotation?: SingleVisitor<t.IntersectionTypeAnnotation, S>,
  MixedTypeAnnotation?: SingleVisitor<t.MixedTypeAnnotation, S>,
  EmptyTypeAnnotation?: SingleVisitor<t.EmptyTypeAnnotation, S>,
  NullableTypeAnnotation?: SingleVisitor<t.NullableTypeAnnotation, S>,
  NumberLiteralTypeAnnotation?: SingleVisitor<t.NumberLiteralTypeAnnotation, S>,
  NumberTypeAnnotation?: SingleVisitor<t.NumberTypeAnnotation, S>,
  ObjectTypeAnnotation?: SingleVisitor<t.ObjectTypeAnnotation, S>,
  ObjectTypeInternalSlot?: SingleVisitor<t.ObjectTypeInternalSlot, S>,
  ObjectTypeCallProperty?: SingleVisitor<t.ObjectTypeCallProperty, S>,
  ObjectTypeIndexer?: SingleVisitor<t.ObjectTypeIndexer, S>,
  ObjectTypeProperty?: SingleVisitor<t.ObjectTypeProperty, S>,
  ObjectTypeSpreadProperty?: SingleVisitor<t.ObjectTypeSpreadProperty, S>,
  OpaqueType?: SingleVisitor<t.OpaqueType, S>,
  QualifiedTypeIdentifier?: SingleVisitor<t.QualifiedTypeIdentifier, S>,
  StringLiteralTypeAnnotation?: SingleVisitor<t.StringLiteralTypeAnnotation, S>,
  StringTypeAnnotation?: SingleVisitor<t.StringTypeAnnotation, S>,
  ThisTypeAnnotation?: SingleVisitor<t.ThisTypeAnnotation, S>,
  TupleTypeAnnotation?: SingleVisitor<t.TupleTypeAnnotation, S>,
  TypeofTypeAnnotation?: SingleVisitor<t.TypeofTypeAnnotation, S>,
  TypeAlias?: SingleVisitor<t.TypeAlias, S>,
  TypeAnnotation?: SingleVisitor<t.TypeAnnotation, S>,
  TypeCastExpression?: SingleVisitor<t.TypeCastExpression, S>,
  TypeParameter?: SingleVisitor<t.TypeParameter, S>,
  TypeParameterDeclaration?: SingleVisitor<t.TypeParameterDeclaration, S>,
  TypeParameterInstantiation?: SingleVisitor<t.TypeParameterInstantiation, S>,
  UnionTypeAnnotation?: SingleVisitor<t.UnionTypeAnnotation, S>,
  Variance?: SingleVisitor<t.Variance, S>,
  VoidTypeAnnotation?: SingleVisitor<t.VoidTypeAnnotation, S>,
  EnumDeclaration?: SingleVisitor<t.EnumDeclaration, S>,
  EnumBooleanBody?: SingleVisitor<t.EnumBooleanBody, S>,
  EnumNumberBody?: SingleVisitor<t.EnumNumberBody, S>,
  EnumStringBody?: SingleVisitor<t.EnumStringBody, S>,
  EnumSymbolBody?: SingleVisitor<t.EnumSymbolBody, S>,
  EnumBooleanMember?: SingleVisitor<t.EnumBooleanMember, S>,
  EnumNumberMember?: SingleVisitor<t.EnumNumberMember, S>,
  EnumStringMember?: SingleVisitor<t.EnumStringMember, S>,
  EnumDefaultedMember?: SingleVisitor<t.EnumDefaultedMember, S>,
  JSXAttribute?: SingleVisitor<t.JSXAttribute, S>,
  JSXClosingElement?: SingleVisitor<t.JSXClosingElement, S>,
  JSXElement?: SingleVisitor<t.JSXElement, S>,
  JSXEmptyExpression?: SingleVisitor<t.JSXEmptyExpression, S>,
  JSXExpressionContainer?: SingleVisitor<t.JSXExpressionContainer, S>,
  JSXSpreadChild?: SingleVisitor<t.JSXSpreadChild, S>,
  JSXIdentifier?: SingleVisitor<t.JSXIdentifier, S>,
  JSXMemberExpression?: SingleVisitor<t.JSXMemberExpression, S>,
  JSXNamespacedName?: SingleVisitor<t.JSXNamespacedName, S>,
  JSXOpeningElement?: SingleVisitor<t.JSXOpeningElement, S>,
  JSXSpreadAttribute?: SingleVisitor<t.JSXSpreadAttribute, S>,
  JSXText?: SingleVisitor<t.JSXText, S>,
  JSXFragment?: SingleVisitor<t.JSXFragment, S>,
  JSXOpeningFragment?: SingleVisitor<t.JSXOpeningFragment, S>,
  JSXClosingFragment?: SingleVisitor<t.JSXClosingFragment, S>,
  Noop?: SingleVisitor<t.Noop, S>,
  Placeholder?: SingleVisitor<t.Placeholder, S>,
  V8IntrinsicIdentifier?: SingleVisitor<t.V8IntrinsicIdentifier, S>,
  ArgumentPlaceholder?: SingleVisitor<t.ArgumentPlaceholder, S>,
  AwaitExpression?: SingleVisitor<t.AwaitExpression, S>,
  BindExpression?: SingleVisitor<t.BindExpression, S>,
  ClassProperty?: SingleVisitor<t.ClassProperty, S>,
  OptionalMemberExpression?: SingleVisitor<t.OptionalMemberExpression, S>,
  PipelineTopicExpression?: SingleVisitor<t.PipelineTopicExpression, S>,
  PipelineBareFunction?: SingleVisitor<t.PipelineBareFunction, S>,
  PipelinePrimaryTopicReference?: SingleVisitor<
    t.PipelinePrimaryTopicReference,
    S,
  >,
  OptionalCallExpression?: SingleVisitor<t.OptionalCallExpression, S>,
  ClassPrivateProperty?: SingleVisitor<t.ClassPrivateProperty, S>,
  ClassPrivateMethod?: SingleVisitor<t.ClassPrivateMethod, S>,
  Import?: SingleVisitor<t.Import, S>,
  Decorator?: SingleVisitor<t.Decorator, S>,
  DoExpression?: SingleVisitor<t.DoExpression, S>,
  ExportDefaultSpecifier?: SingleVisitor<t.ExportDefaultSpecifier, S>,
  ExportNamespaceSpecifier?: SingleVisitor<t.ExportNamespaceSpecifier, S>,
  PrivateName?: SingleVisitor<t.PrivateName, S>,
  BigIntLiteral?: SingleVisitor<t.BigIntLiteral, S>,
  TSParameterProperty?: SingleVisitor<t.TSParameterProperty, S>,
  TSDeclareFunction?: SingleVisitor<t.TSDeclareFunction, S>,
  TSDeclareMethod?: SingleVisitor<t.TSDeclareMethod, S>,
  TSQualifiedName?: SingleVisitor<t.TSQualifiedName, S>,
  TSCallSignatureDeclaration?: SingleVisitor<t.TSCallSignatureDeclaration, S>,
  TSConstructSignatureDeclaration?: SingleVisitor<
    t.TSConstructSignatureDeclaration,
    S,
  >,
  TSPropertySignature?: SingleVisitor<t.TSPropertySignature, S>,
  TSMethodSignature?: SingleVisitor<t.TSMethodSignature, S>,
  TSIndexSignature?: SingleVisitor<t.TSIndexSignature, S>,
  TSAnyKeyword?: SingleVisitor<t.TSAnyKeyword, S>,
  TSBooleanKeyword?: SingleVisitor<t.TSBooleanKeyword, S>,
  TSBigIntKeyword?: SingleVisitor<t.TSBigIntKeyword, S>,
  TSNeverKeyword?: SingleVisitor<t.TSNeverKeyword, S>,
  TSNullKeyword?: SingleVisitor<t.TSNullKeyword, S>,
  TSNumberKeyword?: SingleVisitor<t.TSNumberKeyword, S>,
  TSObjectKeyword?: SingleVisitor<t.TSObjectKeyword, S>,
  TSStringKeyword?: SingleVisitor<t.TSStringKeyword, S>,
  TSSymbolKeyword?: SingleVisitor<t.TSSymbolKeyword, S>,
  TSUndefinedKeyword?: SingleVisitor<t.TSUndefinedKeyword, S>,
  TSUnknownKeyword?: SingleVisitor<t.TSUnknownKeyword, S>,
  TSVoidKeyword?: SingleVisitor<t.TSVoidKeyword, S>,
  TSThisType?: SingleVisitor<t.TSThisType, S>,
  TSFunctionType?: SingleVisitor<t.TSFunctionType, S>,
  TSConstructorType?: SingleVisitor<t.TSConstructorType, S>,
  TSTypeReference?: SingleVisitor<t.TSTypeReference, S>,
  TSTypePredicate?: SingleVisitor<t.TSTypePredicate, S>,
  TSTypeQuery?: SingleVisitor<t.TSTypeQuery, S>,
  TSTypeLiteral?: SingleVisitor<t.TSTypeLiteral, S>,
  TSArrayType?: SingleVisitor<t.TSArrayType, S>,
  TSTupleType?: SingleVisitor<t.TSTupleType, S>,
  TSOptionalType?: SingleVisitor<t.TSOptionalType, S>,
  TSRestType?: SingleVisitor<t.TSRestType, S>,
  TSUnionType?: SingleVisitor<t.TSUnionType, S>,
  TSIntersectionType?: SingleVisitor<t.TSIntersectionType, S>,
  TSConditionalType?: SingleVisitor<t.TSConditionalType, S>,
  TSInferType?: SingleVisitor<t.TSInferType, S>,
  TSParenthesizedType?: SingleVisitor<t.TSParenthesizedType, S>,
  TSTypeOperator?: SingleVisitor<t.TSTypeOperator, S>,
  TSIndexedAccessType?: SingleVisitor<t.TSIndexedAccessType, S>,
  TSMappedType?: SingleVisitor<t.TSMappedType, S>,
  TSLiteralType?: SingleVisitor<t.TSLiteralType, S>,
  TSExpressionWithTypeArguments?: SingleVisitor<
    t.TSExpressionWithTypeArguments,
    S,
  >,
  TSInterfaceDeclaration?: SingleVisitor<t.TSInterfaceDeclaration, S>,
  TSInterfaceBody?: SingleVisitor<t.TSInterfaceBody, S>,
  TSTypeAliasDeclaration?: SingleVisitor<t.TSTypeAliasDeclaration, S>,
  TSAsExpression?: SingleVisitor<t.TSAsExpression, S>,
  TSTypeAssertion?: SingleVisitor<t.TSTypeAssertion, S>,
  TSEnumDeclaration?: SingleVisitor<t.TSEnumDeclaration, S>,
  TSEnumMember?: SingleVisitor<t.TSEnumMember, S>,
  TSModuleDeclaration?: SingleVisitor<t.TSModuleDeclaration, S>,
  TSModuleBlock?: SingleVisitor<t.TSModuleBlock, S>,
  TSImportType?: SingleVisitor<t.TSImportType, S>,
  TSImportEqualsDeclaration?: SingleVisitor<t.TSImportEqualsDeclaration, S>,
  TSExternalModuleReference?: SingleVisitor<t.TSExternalModuleReference, S>,
  TSNonNullExpression?: SingleVisitor<t.TSNonNullExpression, S>,
  TSExportAssignment?: SingleVisitor<t.TSExportAssignment, S>,
  TSNamespaceExportDeclaration?: SingleVisitor<
    t.TSNamespaceExportDeclaration,
    S,
  >,
  TSTypeAnnotation?: SingleVisitor<t.TSTypeAnnotation, S>,
  TSTypeParameterInstantiation?: SingleVisitor<
    t.TSTypeParameterInstantiation,
    S,
  >,
  TSTypeParameterDeclaration?: SingleVisitor<t.TSTypeParameterDeclaration, S>,
  TSTypeParameter?: SingleVisitor<t.TSTypeParameter, S>,
  Expression?: SingleVisitor<t.Expression, S>,
  Binary?: SingleVisitor<t.Binary, S>,
  Scopable?: SingleVisitor<t.Scopable, S>,
  BlockParent?: SingleVisitor<t.BlockParent, S>,
  Block?: SingleVisitor<t.Block, S>,
  Statement?: SingleVisitor<t.Statement, S>,
  Terminatorless?: SingleVisitor<t.Terminatorless, S>,
  CompletionStatement?: SingleVisitor<t.CompletionStatement, S>,
  Conditional?: SingleVisitor<t.Conditional, S>,
  Loop?: SingleVisitor<t.Loop, S>,
  While?: SingleVisitor<t.While, S>,
  ExpressionWrapper?: SingleVisitor<t.ExpressionWrapper, S>,
  For?: SingleVisitor<t.For, S>,
  ForXStatement?: SingleVisitor<t.ForXStatement, S>,
  FunctionParent?: SingleVisitor<t.FunctionParent, S>,
  Pureish?: SingleVisitor<t.Pureish, S>,
  Declaration?: SingleVisitor<t.Declaration, S>,
  PatternLike?: SingleVisitor<t.PatternLike, S>,
  LVal?: SingleVisitor<t.LVal, S>,
  TSEntityName?: SingleVisitor<t.TSEntityName, S>,
  Literal?: SingleVisitor<t.Literal, S>,
  Immutable?: SingleVisitor<t.Immutable, S>,
  UserWhitespacable?: SingleVisitor<t.UserWhitespacable, S>,
  Method?: SingleVisitor<t.Method, S>,
  ObjectMember?: SingleVisitor<t.ObjectMember, S>,
  Property?: SingleVisitor<t.Property, S>,
  UnaryLike?: SingleVisitor<t.UnaryLike, S>,
  Pattern?: SingleVisitor<t.Pattern, S>,
  ModuleDeclaration?: SingleVisitor<t.ModuleDeclaration, S>,
  ExportDeclaration?: SingleVisitor<t.ExportDeclaration, S>,
  ModuleSpecifier?: SingleVisitor<t.ModuleSpecifier, S>,
  Flow?: SingleVisitor<t.Flow, S>,
  FlowType?: SingleVisitor<t.FlowType, S>,
  FlowBaseAnnotation?: SingleVisitor<t.FlowBaseAnnotation, S>,
  FlowDeclaration?: SingleVisitor<t.FlowDeclaration, S>,
  FlowPredicate?: SingleVisitor<t.FlowPredicate, S>,
  EnumBody?: SingleVisitor<t.EnumBody, S>,
  EnumMember?: SingleVisitor<t.EnumMember, S>,
  JSX?: SingleVisitor<t.JSX, S>,
  Private?: SingleVisitor<t.Private, S>,
  TSTypeElement?: SingleVisitor<t.TSTypeElement, S>,
  TSType?: SingleVisitor<t.TSType, S>,
  [string]: SingleVisitor<t.Node, S>,
  ...
};

export type SimpleVisitors<F> = {
  [string]: F | {|enter?: F, exit?: F|},
  shouldSkip?: t.Node => boolean,
  ...
};

export type VisitorsExploded<F> = {
  [string]: {|
    enter?: Array<F>,
    exit?: Array<F>,
  |},
  shouldSkip?: t.Node => boolean,
  ...
};
