/**
 * 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 | {} | () => {};

// 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] | [InlinePlugin, mixed]>,
  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 type TransformOptions = _TransformOptions;
  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;
}

type RawMapping = {
  generated: {column: number, line: number},
  name?: string,
  original?: {column: number, line: number},
  source?: string,
};

declare module 'babel-generator' {
  declare type RawMapping = RawMapping;
  declare function exports(
    ast: _Ast,
    options?: GeneratorOptions,
  ): TransformResult & {rawMappings: ?Array<RawMapping>};
}
