/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

type _SourceMap = {
  version: number,
  file?: string,
  sources: Array<string>,
  names: Array<string>,
  mappings: string,
  sourcesContent?: Array<string>,
};

// based on babylon v6.13.1
type BabylonOptions = {
  allowImportExportEverywhere?: boolean,
  allowReturnOutsideFunction?: boolean,
  allowSuperOutsideMethod?: boolean,
  sourceType?: 'script' | 'module',
  sourceFilename?: 'string',
  plugins?: Array<
    'jsx' | 'flow' | 'doExpressions' | 'objectRestSpread' | 'decorators' |
    'classProperties' | 'exportExtensions' | 'asyncGenerators' |
    'functionBind' | 'functionSent' | 'dynamicImport'
  >,
};

// based on babel-generator v6.18.0
type GeneratorOptions = {
  auxiliaryCommentBefore?: string,
  auxiliaryCommentAfter?: string,
  shouldPrintComment?: (comment: string) => boolean,
  retainLines?: boolean,
  retainFunctionParens?: boolean,
  comments?: boolean,
  compact?: boolean | 'auto',
  minified?: boolean,
  concise?: boolean,
  quotes?: 'single' | 'double',
  filename?: string,
  sourceMaps?: boolean,
  sourceMapTarget?: string,
  sourceRoot?: string,
  sourceFileName?: string,
};

type InlinePlugin = [string | {} | () => {}, any];

// based on https://babeljs.io/docs/usage/options/ -- 2016-11-11
type _TransformOptions = {
  filename?: string,
  filenameRelative?: string,
  presets?: Array<string | Object>,
  plugins?: Array<string | Object | InlinePlugin>,
  parserOpts?: BabylonOptions,
  generatorOpts?: GeneratorOptions,
  highlightCode?: boolean,
  only?: string | RegExp | Array<string | RegExp>,
  ignore?: string | RegExp | Array<string | RegExp>,
  auxiliaryCommentBefore?: boolean,
  auxiliaryCommentAfter?: boolean,
  sourceMaps?: boolean,
  inputSourceMap?: ?Object,
  sourceMapTarget?: string,
  sourceFileName?: string,
  sourceRoot?: string,
  moduleRoot?: string,
  moduleIds?: boolean,
  moduleId?: string,
  getModuleId?: (moduleName: string) => string,
  resolveModuleSource?: (source: string, filename: string) => string,
  code?: boolean,
  babelrc?: boolean,
  ast?: boolean,
  compact?: boolean | 'auto',
  minified?: boolean,
  comments?: boolean,
  shouldPrintComment?: (comment: string) => boolean,
  retainLines?: boolean,
  extends?: string,
};

type TransformOptions =
  _TransformOptions & {env?: {[key: string]: TransformOptions}};
declare class _Ast {};
type TransformResult = {
  ast: _Ast,
  code: ?string,
  map: ?_SourceMap,
};
type VisitFn = <State>(path: Object, state: State) => any;

declare module 'babel-core' {
  declare type SourceMap = _SourceMap;
  declare type Ast = _Ast;
  declare function transform(
    code: string,
    options?: TransformOptions,
  ): TransformResult;
  declare function traverse<State>(
    ast: _Ast,
    visitor: {[key: string]: VisitFn<State> |
                             {enter?: VisitFn<State>, exit?: VisitFn<State>}},
    scope?: ?Object,
    state?: State,
    parentPath?: ?Object,
  ): void;
  declare var types: {[key: string]: Function};
  declare function transformFromAst(
    ast: _Ast,
    code?: ?string,
    babelOptions?: TransformOptions,
  ): TransformResult;
}

declare module 'babel-generator' {
  declare function exports(
    ast: _Ast,
    options?: GeneratorOptions,
  ): TransformResult;
}
