/* tslint:disable */
/* eslint-disable */

export interface Plugin {
  (module: Program): Program;
}

// TODO:
export type ParseOptions = ParserConfig & {
  comments?: boolean;
  script?: boolean;
  /**
   * Defaults to es3.
   */
  target?: JscTarget;
};

export type TerserEcmaVersion = 5 | 2015 | 2016 | string | number;

export interface JsMinifyOptions {
  compress?: TerserCompressOptions | boolean,

  format?: JsFormatOptions & ToSnakeCaseProperties<JsFormatOptions>,

  mangle?: TerserMangleOptions | boolean,

  ecma?: TerserEcmaVersion,

  keep_classnames?: boolean,

  keep_fnames?: boolean,

  module?: boolean,

  safari10?: boolean

  toplevel?: boolean

  sourceMap?: boolean

  outputPath?: string

  inlineSourcesContent?: boolean
}

/**
 * @example ToSnakeCase<'indentLevel'> == 'indent_level'
 */
type ToSnakeCase<T extends string> = T extends `${infer A}${infer B}`
  ? `${A extends Lowercase<A> ? A : `_${Lowercase<A>}`}${ToSnakeCase<B>}`
  : T

/**
 * @example ToSnakeCaseProperties<{indentLevel: 3}> == {indent_level: 3}
 */
type ToSnakeCaseProperties<T> = {
  [K in keyof T as (K extends string ? ToSnakeCase<K> : K)]: T[K]
}

/**
 * These properties are mostly not implemented yet,
 * but it exists to support passing terser config to swc minify
 * without modification.
 */
export interface JsFormatOptions {
  /**
   * Currently noop.
   * @default false
   * @alias ascii_only
   */
  asciiOnly?: boolean

  /**
   * Currently noop.
   * @default false
   */
  beautify?: boolean

  /**
   * Currently noop.
   * @default false
   */
  braces?: boolean

  /**
   * - `false`: removes all comments
   * - `'some'`: preserves some comments
   * - `'all'`: preserves all comments
   * @default false
   */
  comments?: false | 'some' | 'all'

  /**
   * Currently noop.
   * @default 5
   */
  ecma?: TerserEcmaVersion

  /**
   * Currently noop.
   * @alias indent_level
   */
  indentLevel?: number

  /**
   * Currently noop.
   * @alias indent_start
   */
  indentStart?: number

  /**
   * Currently noop.
   * @alias inline_script
   */
  inlineScript?: number

  /**
   * Currently noop.
   * @alias keep_numbers
   */
  keepNumbers?: number

  /**
   * Currently noop.
   * @alias keep_quoted_props
   */
  keepQuotedProps?: boolean

  /**
   * Currently noop.
   * @alias max_line_len
   */
  maxLineLen?: number | false

  /**
   * Currently noop.
   */
  preamble?: string

  /**
   * Currently noop.
   * @alias quote_keys
   */
  quoteKeys?: boolean

  /**
   * Currently noop.
   * @alias quote_style
   */
  quoteStyle?: boolean

  /**
   * Currently noop.
   * @alias preserve_annotations
   */
  preserveAnnotations?: boolean

  /**
   * Currently noop.
   */
  safari10?: boolean

  /**
   * Currently noop.
   */
  semicolons?: boolean

  /**
   * Currently noop.
   */
  shebang?: boolean

  /**
   * Currently noop.
   */
  webkit?: boolean

  /**
   * Currently noop.
   * @alias wrap_iife
   */
  wrapIife?: boolean

  /**
   * Currently noop.
   * @alias wrap_func_args
   */
  wrapFuncArgs?: boolean
}

export interface TerserCompressOptions {
  arguments?: boolean,
  arrows?: boolean,


  booleans?: boolean,


  booleans_as_integers?: boolean,


  collapse_vars?: boolean,


  comparisons?: boolean,


  computed_props?: boolean,


  conditionals?: boolean,


  dead_code?: boolean,

  defaults?: boolean,


  directives?: boolean,


  drop_console?: boolean,


  drop_debugger?: boolean,

  ecma?: TerserEcmaVersion,


  evaluate?: boolean,


  expression?: boolean,


  global_defs?: any,


  hoist_funs?: boolean,


  hoist_props?: boolean,


  hoist_vars?: boolean,


  ie8?: boolean,


  if_return?: boolean,


  inline?: 0 | 1 | 2 | 3


  join_vars?: boolean,


  keep_classnames?: boolean,


  keep_fargs?: boolean,


  keep_fnames?: boolean,


  keep_infinity?: boolean,


  loops?: boolean,
  // module        : false,

  negate_iife?: boolean,


  passes?: number,


  properties?: boolean,


  pure_getters?: any,


  pure_funcs?: string[],


  reduce_funcs?: boolean,


  reduce_vars?: boolean,


  sequences?: any,


  side_effects?: boolean,


  switches?: boolean,


  top_retain?: any,


  toplevel?: any,


  typeofs?: boolean,


  unsafe?: boolean,


  unsafe_passes?: boolean,


  unsafe_arrows?: boolean,


  unsafe_comps?: boolean,


  unsafe_function?: boolean,


  unsafe_math?: boolean,


  unsafe_symbols?: boolean,


  unsafe_methods?: boolean,


  unsafe_proto?: boolean,


  unsafe_regexp?: boolean,


  unsafe_undefined?: boolean,


  unused?: boolean,


  module?: boolean,
}

export interface TerserMangleOptions {
  props?: TerserManglePropertiesOptions,

  toplevel?: boolean,

  keep_classnames?: boolean,

  keep_fnames?: boolean,

  keep_private_props?: boolean,

  ie8?: boolean,

  safari10?: boolean,

  reserved?: string[],
}

export interface TerserManglePropertiesOptions {

}


/**
 * Programmatic options.
 */
export interface Options extends Config {
  /**
   * If true, a file is parsed as a script instead of module.
   */
  script?: boolean;

  /**
   * The working directory that all paths in the programmatic
   * options will be resolved relative to.
   *
   * Defaults to `process.cwd()`.
   */
  cwd?: string;
  caller?: CallerOptions;
  /** The filename associated with the code currently being compiled,
   * if there is one. The filename is optional, but not all of Swc's
   * functionality is available when the filename is unknown, because a
   * subset of options rely on the filename for their functionality.
   *
   * The three primary cases users could run into are:
   *
   * - The filename is exposed to plugins. Some plugins may require the
   * presence of the filename.
   * - Options like "test", "exclude", and "ignore" require the filename
   * for string/RegExp matching.
   * - .swcrc files are loaded relative to the file being compiled.
   * If this option is omitted, Swc will behave as if swcrc: false has been set.
   */
  filename?: string;

  /**
   * The initial path that will be processed based on the "rootMode" to
   * determine the conceptual root folder for the current Swc project.
   * This is used in two primary cases:
   *
   * - The base directory when checking for the default "configFile" value
   * - The default value for "swcrcRoots".
   *
   * Defaults to `opts.cwd`
   */
  root?: string;

  /**
   * This option, combined with the "root" value, defines how Swc chooses
   * its project root. The different modes define different ways that Swc
   * can process the "root" value to get the final project root.
   *
   * "root" - Passes the "root" value through as unchanged.
   * "upward" - Walks upward from the "root" directory, looking for a directory
   * containing a swc.config.js file, and throws an error if a swc.config.js
   * is not found.
   * "upward-optional" - Walk upward from the "root" directory, looking for
   * a directory containing a swc.config.js file, and falls back to "root"
   *  if a swc.config.js is not found.
   *
   *
   * "root" is the default mode because it avoids the risk that Swc
   * will accidentally load a swc.config.js that is entirely outside
   * of the current project folder. If you use "upward-optional",
   * be aware that it will walk up the directory structure all the
   * way to the filesystem root, and it is always possible that someone
   * will have a forgotten swc.config.js in their home directory,
   * which could cause unexpected errors in your builds.
   *
   *
   * Users with monorepo project structures that run builds/tests on a
   * per-package basis may well want to use "upward" since monorepos
   * often have a swc.config.js in the project root. Running Swc
   * in a monorepo subdirectory without "upward", will cause Swc
   * to skip loading any swc.config.js files in the project root,
   * which can lead to unexpected errors and compilation failure.
   */
  rootMode?: "root" | "upward" | "upward-optional";

  /**
   * The current active environment used during configuration loading.
   * This value is used as the key when resolving "env" configs,
   * and is also available inside configuration functions, plugins,
   * and presets, via the api.env() function.
   *
   * Defaults to `process.env.SWC_ENV || process.env.NODE_ENV || "development"`
   */
  envName?: string;

  /**
   * Defaults to searching for a default `.swcrc` file, but can
   * be passed the path of any JS or JSON5 config file.
   *
   *
   * NOTE: This option does not affect loading of .swcrc files,
   * so while it may be tempting to do configFile: "./foo/.swcrc",
   * it is not recommended. If the given .swcrc is loaded via the
   * standard file-relative logic, you'll end up loading the same
   * config file twice, merging it with itself. If you are linking
   * a specific config file, it is recommended to stick with a
   * naming scheme that is independent of the "swcrc" name.
   *
   * Defaults to `path.resolve(opts.root, ".swcrc")`
   */
  configFile?: string | boolean;

  /**
   * true will enable searching for configuration files relative to the "filename" provided to Swc.
   *
   * A swcrc value passed in the programmatic options will override one set within a configuration file.
   *
   * Note: .swcrc files are only loaded if the current "filename" is inside of
   *  a package that matches one of the "swcrcRoots" packages.
   *
   *
   * Defaults to true as long as the filename option has been specified
   */
  swcrc?: boolean;

  /**
   * By default, Babel will only search for .babelrc files within the "root" package
   *  because otherwise Babel cannot know if a given .babelrc is meant to be loaded,
   *  or if it's "plugins" and "presets" have even been installed, since the file
   *  being compiled could be inside node_modules, or have been symlinked into the project.
   *
   *
   * This option allows users to provide a list of other packages that should be
   * considered "root" packages when considering whether to load .babelrc files.
   *
   *
   * For example, a monorepo setup that wishes to allow individual packages
   * to have their own configs might want to do
   *
   *
   *
   * Defaults to `opts.root`
   */
  swcrcRoots?: boolean | MatchPattern | MatchPattern[];

  /**
   * `true` will attempt to load an input sourcemap from the file itself, if it
   * contains a //# sourceMappingURL=... comment. If no map is found, or the
   * map fails to load and parse, it will be silently discarded.
   *
   *  If an object is provided, it will be treated as the source map object itself.
   *
   * Defaults to `true`.
   */
  inputSourceMap?: boolean | string;

  /**
   * The name to use for the file inside the source map object.
   *
   * Defaults to `path.basename(opts.filenameRelative)` when available, or `"unknown"`.
   */
  sourceFileName?: string;

  /**
   * The sourceRoot fields to set in the generated source map, if one is desired.
   */
  sourceRoot?: string;

  plugin?: Plugin;

  isModule?: boolean | 'unknown';

  /**
   * Destination path. Note that this value is used only to fix source path
   * of source map files and swc does not write output to this path.
   */
  outputPath?: string
}

export interface CallerOptions {
  name: string;
  [key: string]: any;
}

export type Swcrc = Config | Config[];

/**
 * .swcrc
 */
export interface Config {
  /**
   * Note: The type is string because it follows rust's regex syntax.
   */
  test?: string | string[];
  /**
   * Note: The type is string because it follows rust's regex syntax.
   */
  exclude?: string | string[];
  env?: EnvConfig;
  jsc?: JscConfig;
  module?: ModuleConfig;
  minify?: boolean;

  /**
   * - true to generate a sourcemap for the code and include it in the result object.
   * - "inline" to generate a sourcemap and append it as a data URL to the end of the code, but not include it in the result object.
   *
   * `swc-cli` overloads some of these to also affect how maps are written to disk:
   *
   * - true will write the map to a .map file on disk
   * - "inline" will write the file directly, so it will have a data: containing the map
   * - Note: These options are bit weird, so it may make the most sense to just use true
   *  and handle the rest in your own code, depending on your use case.
   */
  sourceMaps?: boolean | "inline";

  inlineSourcesContent?: boolean
}

/**
 * Configuration ported from babel-preset-env
 */
export interface EnvConfig {
  mode?: "usage" | "entry";
  debug?: boolean;
  dynamicImport?: boolean;

  loose?: boolean;

  /// Skipped es features.
  ///
  /// e.g.)
  ///  - `core-js/modules/foo`
  skip?: string[];

  include?: string[];

  exclude?: string[];

  /**
   * The version of the used core js.
   *
   */
  coreJs?: string;

  targets?: any;

  path?: string;

  shippedProposals?: boolean;

  /**
   * Enable all transforms
   */
  forceAllTransforms?: boolean;
}

export interface JscConfig {
  loose?: boolean;

  /**
   * Defaults to EsParserConfig
   */
  parser?: ParserConfig;
  transform?: TransformConfig;
  /**
   * Use `@swc/helpers` instead of inline helpers.
   */
  externalHelpers?: boolean;

  /**
   * Defaults to `es3` (which enabled **all** pass).
   */
  target?: JscTarget;

  /**
   * Keep class names.
   */
  keepClassNames?: boolean

  experimental?: {
    optimizeHygiene?: boolean,
    keepImportAssertions?: boolean,
    /**
     * Specify the location where SWC stores its intermediate cache files.
     * Currently only transform plugin uses this. If not specified, SWC will
     * create `.swc` directories.
     */
    cacheRoot?: string;
    /**
     * List of custom transform plugins written in WebAssembly.
     * First parameter of tuple indicates the name of the plugin - it can be either
     * a name of the npm package can be resolved, or absolute path to .wasm binary.
     *
     * Second parameter of tuple is JSON based configuration for the plugin.
     */
    plugins?: Array<[string, Record<string, any>]>
  },

  baseUrl?: string

  paths?: {
    [from: string]: string[]
  }

  minify?: JsMinifyOptions;

  preserveAllComments?: boolean;
}

export type JscTarget =
  | "es3"
  | "es5"
  | "es2015"
  | "es2016"
  | "es2017"
  | "es2018"
  | "es2019"
  | "es2020"
  | "es2021"
  | "es2022";

export type ParserConfig = TsParserConfig | EsParserConfig;
export interface TsParserConfig {
  syntax: "typescript";
  /**
   * Defaults to `false`.
   */
  tsx?: boolean;
  /**
   * Defaults to `false`.
   */
  decorators?: boolean;
  /**
   * Defaults to `false`
   */
  dynamicImport?: boolean;
}

export interface EsParserConfig {
  syntax: "ecmascript";
  /**
   * Defaults to false.
   */
  jsx?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  numericSeparator?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  classPrivateProperty?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  privateMethod?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  classProperty?: boolean;
  /**
   * Defaults to `false`
   */
  functionBind?: boolean;
  /**
   * Defaults to `false`
   */
  decorators?: boolean;
  /**
   * Defaults to `false`
   */
  decoratorsBeforeExport?: boolean;
  /**
   * Defaults to `false`
   */
  exportDefaultFrom?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  exportNamespaceFrom?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  dynamicImport?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  nullishCoalescing?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  optionalChaining?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  importMeta?: boolean;
  /**
   * @deprecated Always true because it's in ecmascript spec.
   */
  topLevelAwait?: boolean;
  /**
   * Defaults to `false`
   */
  importAssertions?: boolean;
}

/**
 * Options for transform.
 */
export interface TransformConfig {
  /**
   * Effective only if `syntax` supports ƒ.
   */
  react?: ReactConfig;

  constModules?: ConstModulesConfig;

  /**
   * Defaults to null, which skips optimizer pass.
   */
  optimizer?: OptimizerConfig;

  /**
   * https://swc.rs/docs/configuring-swc.html#jsctransformlegacydecorator
   */
  legacyDecorator?: boolean;

  /**
   * https://swc.rs/docs/configuring-swc.html#jsctransformdecoratormetadata
   */
  decoratorMetadata?: boolean;

  treatConstEnumAsEnum?: boolean;

  useDefineForClassFields?: boolean;
}

export interface ReactConfig {
  /**
   * Replace the function used when compiling JSX expressions.
   *
   * Defaults to `React.createElement`.
   */
  pragma?: string;
  /**
   * Replace the component used when compiling JSX fragments.
   *
   * Defaults to `React.Fragment`
   */
  pragmaFrag?: string;
  /**
   * Toggles whether or not to throw an error if a XML namespaced tag name is used. For example:
   * `<f:image />`
   *
   * Though the JSX spec allows this, it is disabled by default since React's
   * JSX does not currently have support for it.
   *
   */
  throwIfNamespace?: boolean;
  /**
   * Toggles plugins that aid in development, such as @swc/plugin-transform-react-jsx-self
   * and @swc/plugin-transform-react-jsx-source.
   *
   * Defaults to `false`,
   *
   */
  development?: boolean;
  /**
   * Use `Object.assign()` instead of `_extends`. Defaults to false.
   * @deprecated
   */
  useBuiltins?: boolean;

  /**
   * Enable fast refresh feature for React app
   */
  refresh?: boolean;

  /**
   * jsx runtime
   */
  runtime?: 'automatic' | 'classic'

  /**
   * Declares the module specifier to be used for importing the `jsx` and `jsxs` factory functions when using `runtime` 'automatic'
   */
  importSource?: string
}
/**
 *  - `import { DEBUG } from '@ember/env-flags';`
 *  - `import { FEATURE_A, FEATURE_B } from '@ember/features';`
 *
 * See: https://github.com/swc-project/swc/issues/18#issuecomment-466272558
 */
export interface ConstModulesConfig {
  globals?: {
    [module: string]: {
      [name: string]: string;
    };
  };
}

/// https://swc.rs/docs/configuring-swc.html#jsctransformoptimizerjsonify
export interface OptimizerConfig {
  /// https://swc.rs/docs/configuration/compilation#jsctransformoptimizersimplify
  simplify?: boolean;
  /// https://swc.rs/docs/configuring-swc.html#jsctransformoptimizerglobals
  globals?: GlobalPassOption;
  /// https://swc.rs/docs/configuring-swc.html#jsctransformoptimizerjsonify
  jsonify?: { minCost: number };
}

/**
 * Options for inline-global pass.
 */
export interface GlobalPassOption {
  /**
   * Global variables.
   *
   * e.g. `{ __DEBUG__: true }`
   */
  vars?: { [key: string]: string };

  /**
   * Name of environment variables to inline.
   *
   * Defaults to `["NODE_ENV", "SWC_ENV"]`
   */
  envs?: string[];
}

export type ModuleConfig = Es6Config | CommonJsConfig | UmdConfig | AmdConfig | NodeNextConfig | SystemjsConfig;

export interface BaseModuleConfig {
  /**
   * By default, when using exports with babel a non-enumerable `__esModule`
   * property is exported. In some cases this property is used to determine
   * if the import is the default export or if it contains the default export.
   *
   * In order to prevent the __esModule property from being exported, you
   *  can set the strict option to true.
   *
   * Defaults to `false`.
   */
  strict?: boolean;

  /**
   * Emits 'use strict' directive.
   *
   * Defaults to `true`.
   */
  strictMode?: boolean;

  /**
   * Changes Babel's compiled import statements to be lazily evaluated when their imported bindings are used for the first time.
   *
   * This can improve initial load time of your module because evaluating dependencies up
   *  front is sometimes entirely un-necessary. This is especially the case when implementing
   *  a library module.
   *
   *
   * The value of `lazy` has a few possible effects:
   *
   *  - `false` - No lazy initialization of any imported module.
   *  - `true` - Do not lazy-initialize local `./foo` imports, but lazy-init `foo` dependencies.
   *
   * Local paths are much more likely to have circular dependencies, which may break if loaded lazily,
   * so they are not lazy by default, whereas dependencies between independent modules are rarely cyclical.
   *
   *  - `Array<string>` - Lazy-initialize all imports with source matching one of the given strings.
   *
   * -----
   *
   * The two cases where imports can never be lazy are:
   *
   *  - `import "foo";`
   *
   * Side-effect imports are automatically non-lazy since their very existence means
   *  that there is no binding to later kick off initialization.
   *
   *  - `export * from "foo"`
   *
   * Re-exporting all names requires up-front execution because otherwise there is no
   * way to know what names need to be exported.
   *
   * Defaults to `false`.
   */
  lazy?: boolean | string[];
  /**
   * @deprecated  Use the `importInterop` option instead.
   *
   * By default, when using exports with swc a non-enumerable __esModule property is exported.
   * This property is then used to determine if the import is the default export or if
   *  it contains the default export.
   *
   * In cases where the auto-unwrapping of default is not needed, you can set the noInterop option
   *  to true to avoid the usage of the interopRequireDefault helper (shown in inline form above).
   *
   * Defaults to `false`.
   */
  noInterop?: boolean;
  /**
   * Defaults to `swc`.
   *
   * CommonJS modules and ECMAScript modules are not fully compatible.
   * However, compilers, bundlers and JavaScript runtimes developed different strategies
   * to make them work together as well as possible.
   *
   * - `swc` (alias: `babel`)
   *
   * When using exports with `swc` a non-enumerable `__esModule` property is exported
   * This property is then used to determine if the import is the default export
   * or if it contains the default export.
   *
   * ```javascript
   * import foo from "foo";
   * import { bar } from "bar";
   * foo;
   * bar;
   *
   * // Is compiled to ...
   *
   * "use strict";
   *
   * function _interop_require_default(obj) {
   *   return obj && obj.__esModule ? obj : { default: obj };
   * }
   *
   * var _foo = _interop_require_default(require("foo"));
   * var _bar = require("bar");
   *
   * _foo.default;
   * _bar.bar;
   * ```
   *
   * When this import interop is used, if both the imported and the importer module are compiled
   * with swc they behave as if none of them was compiled.
   *
   * This is the default behavior.
   *
   * - `node`
   *
   * When importing CommonJS files (either directly written in CommonJS, or generated with a compiler)
   * Node.js always binds the `default` export to the value of `module.exports`.
   *
   * ```javascript
   * import foo from "foo";
   * import { bar } from "bar";
   * foo;
   * bar;
   *
   * // Is compiled to ...
   *
   * "use strict";
   *
   * var _foo = require("foo");
   * var _bar = require("bar");
   *
   * _foo;
   * _bar.bar;
   * ```
   * This is not exactly the same as what Node.js does since swc allows accessing any property of `module.exports`
   * as a named export, while Node.js only allows importing statically analyzable properties of `module.exports`.
   * However, any import working in Node.js will also work when compiled with swc using `importInterop: "node"`.
   *
   * - `none`
   *
   * If you know that the imported file has been transformed with a compiler that stores the `default` export on
   * `exports.default` (such as swc or Babel), you can safely omit the `_interop_require_default` helper.
   *
   * ```javascript
   * import foo from "foo";
   * import { bar } from "bar";
   * foo;
   * bar;
   *
   * // Is compiled to ...
   *
   * "use strict";
   *
   * var _foo = require("foo");
   * var _bar = require("bar");
   *
   * _foo.default;
   * _bar.bar;
   * ```
   */
  importInterop?: "swc" | "babel" | "node" | "none";
  /**
   * Emits `cjs-module-lexer` annotation
   * `cjs-module-lexer` is used in Node.js core for detecting the named exports available when importing a CJS module into ESM.
   * swc will emit `cjs-module-lexer` detectable annotation with this option enabled.
   * 
   * Defaults to `true` if import_interop is Node, else `false`
   */
  exportInteropAnnotation?: boolean;
  /**
   * If set to true, dynamic imports will be preserved.
   */
  ignoreDynamic?: boolean;
  allowTopLevelThis?: boolean;
  preserveImportMeta?: boolean;
}

export interface Es6Config extends BaseModuleConfig {
  type: "es6";
}

export interface NodeNextConfig extends BaseModuleConfig {
  type: "nodenext";
}

export interface CommonJsConfig extends BaseModuleConfig {
  type: "commonjs";
}

export interface UmdConfig extends BaseModuleConfig {
  type: "umd";
  globals?: { [key: string]: string };
}

export interface AmdConfig extends BaseModuleConfig {
  type: "amd";
  moduleId?: string;
}
export interface SystemjsConfig {
  type: "systemjs";
  allowTopLevelThis?: boolean;
}
export interface Output {
  /**
   * Transformed code
   */
  code: string;
  /**
   * Sourcemap (**not** base64 encoded)
   */
  map?: string;
}

export interface MatchPattern { }

// -------------------------------
// ---------- Ast nodes ----------
// -------------------------------

export interface Span {
  start: number;
  end: number;
  ctxt: number;
}

export interface Node {
  type: string;
}

export interface HasSpan {
  span: Span;
}

export interface HasDecorator {
  decorators?: Decorator[];
}

export interface Class extends HasSpan, HasDecorator {
  body: ClassMember[];

  superClass?: Expression;

  isAbstract: boolean;

  typeParams?: TsTypeParameterDeclaration;

  superTypeParams?: TsTypeParameterInstantiation;

  implements: TsExpressionWithTypeArguments[];
}

export type ClassMember =
  | Constructor
  | ClassMethod
  | PrivateMethod
  | ClassProperty
  | PrivateProperty
  | TsIndexSignature
  | EmptyStatement
  | StaticBlock;

export interface ClassPropertyBase extends Node, HasSpan, HasDecorator {
  value?: Expression;

  typeAnnotation?: TsTypeAnnotation;

  isStatic: boolean;

  accessibility?: Accessibility;

  isOptional: boolean;

  isOverride: boolean;

  readonly: boolean;

  definite: boolean;
}

export interface ClassProperty extends ClassPropertyBase {
  type: "ClassProperty";

  key: PropertyName;

  isAbstract: boolean;

  declare: boolean;
}

export interface PrivateProperty extends ClassPropertyBase {
  type: "PrivateProperty";

  key: PrivateName;
}

export interface Param extends Node, HasSpan, HasDecorator {
  type: "Parameter";
  pat: Pattern;
}

export interface Constructor extends Node, HasSpan {
  type: "Constructor";

  key: PropertyName;

  params: (TsParameterProperty | Param)[];

  body?: BlockStatement;

  accessibility?: Accessibility;

  isOptional: boolean;
}

export interface ClassMethodBase extends Node, HasSpan {
  function: Fn;

  kind: MethodKind;

  isStatic: boolean;

  accessibility?: Accessibility;

  isAbstract: boolean;

  isOptional: boolean;

  isOverride: boolean;
}

export interface ClassMethod extends ClassMethodBase {
  type: "ClassMethod";

  key: PropertyName;
}

export interface PrivateMethod extends ClassMethodBase {
  type: "PrivateMethod";

  key: PrivateName;
}

export interface StaticBlock extends Node, HasSpan {
  type: "StaticBlock";

  body: BlockStatement;
}

export interface Decorator extends Node, HasSpan {
  type: "Decorator";

  expression: Expression;
}

export type MethodKind = "method" | "getter" | "setter";

export type Declaration =
  | ClassDeclaration
  | FunctionDeclaration
  | VariableDeclaration
  | TsInterfaceDeclaration
  | TsTypeAliasDeclaration
  | TsEnumDeclaration
  | TsModuleDeclaration;

export interface FunctionDeclaration extends Fn {
  type: "FunctionDeclaration";

  identifier: Identifier;

  declare: boolean;
}

export interface ClassDeclaration extends Class, Node {
  type: "ClassDeclaration";

  identifier: Identifier;

  declare: boolean;
}

export interface VariableDeclaration extends Node, HasSpan {
  type: "VariableDeclaration";

  kind: VariableDeclarationKind;

  declare: boolean;

  declarations: VariableDeclarator[];
}

export type VariableDeclarationKind = "var" | "let" | "const";

export interface VariableDeclarator extends Node, HasSpan {
  type: "VariableDeclarator";

  id: Pattern;

  /// Initialization expression.
  init?: Expression;

  /// Typescript only
  definite: boolean;
}

export type Expression =
  | ThisExpression
  | ArrayExpression
  | ObjectExpression
  | FunctionExpression
  | UnaryExpression
  | UpdateExpression
  | BinaryExpression
  | AssignmentExpression
  | MemberExpression
  | SuperPropExpression
  | ConditionalExpression
  | CallExpression
  | NewExpression
  | SequenceExpression
  | Identifier
  | Literal
  | TemplateLiteral
  | TaggedTemplateExpression
  | ArrowFunctionExpression
  | ClassExpression
  | YieldExpression
  | MetaProperty
  | AwaitExpression
  | ParenthesisExpression
  | JSXMemberExpression
  | JSXNamespacedName
  | JSXEmptyExpression
  | JSXElement
  | JSXFragment
  | TsTypeAssertion
  | TsConstAssertion
  | TsNonNullExpression
  | TsAsExpression
  | TsInstantiation
  | PrivateName
  | OptionalChainingExpression
  | Invalid;

interface ExpressionBase extends Node, HasSpan { }

export interface Identifier extends ExpressionBase {
  type: "Identifier";

  value: string;

  /// TypeScript only. Used in case of an optional parameter.
  optional: boolean;
}

export interface OptionalChainingExpression extends ExpressionBase {
  type: "OptionalChainingExpression";
  questionDotToken: Span;
  /**
   * Call expression or member expression.
   */
  base: MemberExpression | OptionalChainingCall;
}

export interface OptionalChainingCall extends ExpressionBase {
  type: "CallExpression";
  callee: Expression;
  arguments: ExprOrSpread[];
  typeArguments?: TsTypeParameterInstantiation;
}

export interface ThisExpression extends ExpressionBase {
  type: "ThisExpression";
}

export interface ArrayExpression extends ExpressionBase {
  type: "ArrayExpression";

  elements: (ExprOrSpread | undefined)[];
}

export interface ExprOrSpread {
  spread?: Span;
  expression: Expression;
}

export interface ObjectExpression extends ExpressionBase {
  type: "ObjectExpression";

  properties: (SpreadElement | Property)[];
}

export interface Argument {
  spread?: Span;
  expression: Expression;
}

export interface SpreadElement extends Node {
  type: "SpreadElement";

  spread: Span;

  arguments: Expression;
}

export interface UnaryExpression extends ExpressionBase {
  type: "UnaryExpression";

  operator: UnaryOperator;

  argument: Expression;
}

export interface UpdateExpression extends ExpressionBase {
  type: "UpdateExpression";

  operator: UpdateOperator;

  prefix: boolean;

  argument: Expression;
}

export interface BinaryExpression extends ExpressionBase {
  type: "BinaryExpression";

  operator: BinaryOperator;

  left: Expression;

  right: Expression;
}

export interface FunctionExpression extends Fn, ExpressionBase {
  type: "FunctionExpression";

  identifier?: Identifier;
}

export interface ClassExpression extends Class, ExpressionBase {
  type: "ClassExpression";

  identifier?: Identifier;
}

export interface AssignmentExpression extends ExpressionBase {
  type: "AssignmentExpression";

  operator: AssignmentOperator;

  left: Expression | Pattern;

  right: Expression;
}

export interface MemberExpression extends ExpressionBase {
  type: "MemberExpression";

  object: Expression;

  property: Identifier | PrivateName | ComputedPropName;
}

export interface SuperPropExpression extends ExpressionBase {
  type: "SuperPropExpression";

  obj: Super;

  property: Identifier | ComputedPropName;
}

export interface ConditionalExpression extends ExpressionBase {
  type: "ConditionalExpression";

  test: Expression;

  consequent: Expression;

  alternate: Expression;
}

export interface Super extends Node, HasSpan {
  type: "Super";
}

export interface Import extends Node, HasSpan {
  type: "Import";
}

export interface CallExpression extends ExpressionBase {
  type: "CallExpression";

  callee: Super | Import | Expression;

  arguments: Argument[];

  typeArguments?: TsTypeParameterInstantiation;
}

export interface NewExpression extends ExpressionBase {
  type: "NewExpression";

  callee: Expression;

  arguments?: Argument[];

  typeArguments?: TsTypeParameterInstantiation;
}

export interface SequenceExpression extends ExpressionBase {
  type: "SequenceExpression";

  expressions: Expression[];
}

export interface ArrowFunctionExpression extends ExpressionBase {
  type: "ArrowFunctionExpression";

  params: Pattern[];

  body: BlockStatement | Expression;

  async: boolean;

  generator: boolean;

  typeParameters?: TsTypeParameterDeclaration;

  returnType?: TsTypeAnnotation;
}

export interface YieldExpression extends ExpressionBase {
  type: "YieldExpression";

  argument?: Expression;

  delegate: boolean;
}

export interface MetaProperty extends Node, HasSpan {
  type: "MetaProperty";

  kind: "new.target" | "import.meta";
}

export interface AwaitExpression extends ExpressionBase {
  type: "AwaitExpression";

  argument: Expression;
}

export interface TemplateLiteral extends ExpressionBase {
  type: "TemplateLiteral";

  expressions: Expression[];

  quasis: TemplateElement[];
}

export interface TaggedTemplateExpression extends ExpressionBase {
  type: "TaggedTemplateExpression";

  tag: Expression;

  typeParameters?: TsTypeParameterInstantiation;

  template: TemplateLiteral;
}

export interface TemplateElement extends ExpressionBase {
  type: "TemplateElement";

  tail: boolean;
  cooked?: string;
  raw: string;
}

export interface ParenthesisExpression extends ExpressionBase {
  type: "ParenthesisExpression";

  expression: Expression;
}

export interface Fn extends HasSpan, HasDecorator {
  params: Param[];

  body?: BlockStatement;

  generator: boolean;

  async: boolean;

  typeParameters?: TsTypeParameterDeclaration;

  returnType?: TsTypeAnnotation;
}

interface PatternBase extends Node, HasSpan {
  typeAnnotation?: TsTypeAnnotation;
}

export interface PrivateName extends ExpressionBase {
  type: "PrivateName";

  id: Identifier;
}

export type JSXObject = JSXMemberExpression | Identifier;

export interface JSXMemberExpression extends Node {
  type: "JSXMemberExpression";

  object: JSXObject;
  property: Identifier;
}

/**
 * XML-based namespace syntax:
 */
export interface JSXNamespacedName extends Node {
  type: "JSXNamespacedName";

  namespace: Identifier;
  name: Identifier;
}

export interface JSXEmptyExpression extends Node, HasSpan {
  type: "JSXEmptyExpression";
}

export interface JSXExpressionContainer extends Node, HasSpan {
  type: "JSXExpressionContainer";

  expression: JSXExpression;
}

export type JSXExpression = JSXEmptyExpression | Expression;

export interface JSXSpreadChild extends Node, HasSpan {
  type: "JSXSpreadChild";

  expression: Expression;
}

export type JSXElementName =
  | Identifier
  | JSXMemberExpression
  | JSXNamespacedName;

export interface JSXOpeningElement extends Node, HasSpan {
  type: "JSXOpeningElement";

  name: JSXElementName;

  attributes: JSXAttributeOrSpread[];

  selfClosing: boolean;

  typeArguments?: TsTypeParameterInstantiation;
}

export type JSXAttributeOrSpread = JSXAttribute | SpreadElement;

export interface JSXClosingElement extends Node, HasSpan {
  type: "JSXClosingElement";

  name: JSXElementName;
}

export interface JSXAttribute extends Node, HasSpan {
  type: "JSXAttribute";

  name: JSXAttributeName;

  value?: JSXAttrValue;
}

export type JSXAttributeName = Identifier | JSXNamespacedName;

export type JSXAttrValue =
  | Literal
  | JSXExpressionContainer
  | JSXElement
  | JSXFragment;

export interface JSXText extends Node, HasSpan {
  type: "JSXText";

  value: string;
  raw: string;
}

export interface JSXElement extends Node, HasSpan {
  type: "JSXElement";

  opening: JSXOpeningElement;
  children: JSXElementChild[];
  closing?: JSXClosingElement;
}

export type JSXElementChild =
  | JSXText
  | JSXExpressionContainer
  | JSXSpreadChild
  | JSXElement
  | JSXFragment;

export interface JSXFragment extends Node, HasSpan {
  type: "JSXFragment";

  opening: JSXOpeningFragment;

  children: JSXElementChild[];

  closing: JSXClosingFragment;
}

export interface JSXOpeningFragment extends Node, HasSpan {
  type: "JSXOpeningFragment";
}

export interface JSXClosingFragment extends Node, HasSpan {
  type: "JSXClosingFragment";
}

export type Literal =
  | StringLiteral
  | BooleanLiteral
  | NullLiteral
  | NumericLiteral
  | BigIntLiteral
  | RegExpLiteral
  | JSXText;

export interface StringLiteral extends Node, HasSpan {
  type: "StringLiteral";

  value: string;

  raw?: string;
}

export interface BooleanLiteral extends Node, HasSpan {
  type: "BooleanLiteral";

  value: boolean;
}

export interface NullLiteral extends Node, HasSpan {
  type: "NullLiteral";
}

export interface RegExpLiteral extends Node, HasSpan {
  type: "RegExpLiteral";

  pattern: string;
  flags: string;
}

export interface NumericLiteral extends Node, HasSpan {
  type: "NumericLiteral";

  value: number;

  raw?: string;
}

export interface BigIntLiteral extends Node, HasSpan {
  type: "BigIntLiteral";

  value: bigint;

  raw?: string;
}

export type ModuleDeclaration =
  | ImportDeclaration
  | ExportDeclaration
  | ExportNamedDeclaration
  | ExportDefaultDeclaration
  | ExportDefaultExpression
  | ExportAllDeclaration
  | TsImportEqualsDeclaration
  | TsExportAssignment
  | TsNamespaceExportDeclaration;

export interface ExportDefaultExpression extends Node, HasSpan {
  type: "ExportDefaultExpression";

  expression: Expression;
}

export interface ExportDeclaration extends Node, HasSpan {
  type: "ExportDeclaration";

  declaration: Declaration;
}

export interface ImportDeclaration extends Node, HasSpan {
  type: "ImportDeclaration";

  specifiers: ImportSpecifier[];

  source: StringLiteral;

  typeOnly: boolean;

  asserts?: ObjectExpression;
}

export interface ExportAllDeclaration extends Node, HasSpan {
  type: "ExportAllDeclaration";

  source: StringLiteral;

  asserts?: ObjectExpression;
}

/**
 * - `export { foo } from 'mod'`
 * - `export { foo as bar } from 'mod'`
 */
export interface ExportNamedDeclaration extends Node, HasSpan {
  type: "ExportNamedDeclaration";

  specifiers: ExportSpecifier[];

  source?: StringLiteral;

  typeOnly: boolean;

  asserts?: ObjectExpression;
}

export interface ExportDefaultDeclaration extends Node, HasSpan {
  type: "ExportDefaultDeclaration";

  decl: DefaultDecl;
}

export type DefaultDecl =
  | ClassExpression
  | FunctionExpression
  | TsInterfaceDeclaration;

export type ImportSpecifier =
  | NamedImportSpecifier
  | ImportDefaultSpecifier
  | ImportNamespaceSpecifier;

/**
 * e.g. `import foo from 'mod.js'`
 */
export interface ImportDefaultSpecifier extends Node, HasSpan {
  type: "ImportDefaultSpecifier";
  local: Identifier;
}

/**
 * e.g. `import * as foo from 'mod.js'`.
 */
export interface ImportNamespaceSpecifier extends Node, HasSpan {
  type: "ImportNamespaceSpecifier";

  local: Identifier;
}

/**
 * e.g. - `import { foo } from 'mod.js'`
 *
 * local = foo, imported = None
 *
 * e.g. `import { foo as bar } from 'mod.js'`
 *
 * local = bar, imported = Some(foo) for
 */
export interface NamedImportSpecifier extends Node, HasSpan {
  type: "ImportSpecifier";
  local: Identifier;
  imported?: ModuleExportName;
  isTypeOnly: boolean;
}

export type ModuleExportName = Identifier | StringLiteral;

export type ExportSpecifier =
  | ExportNamespaceSpecifier
  | ExportDefaultSpecifier
  | NamedExportSpecifier;

/**
 * `export * as foo from 'src';`
 */
export interface ExportNamespaceSpecifier extends Node, HasSpan {
  type: "ExportNamespaceSpecifier";

  name: ModuleExportName;
}

export interface ExportDefaultSpecifier extends Node, HasSpan {
  type: "ExportDefaultSpecifier";

  exported: Identifier;
}

export interface NamedExportSpecifier extends Node, HasSpan {
  type: "ExportSpecifier";

  orig: ModuleExportName;
  /**
   * `Some(bar)` in `export { foo as bar }`
   */
  exported?: ModuleExportName;
  isTypeOnly: boolean;
}

interface HasInterpreter {
  /**
   * e.g. `/usr/bin/node` for `#!/usr/bin/node`
   */
  interpreter: string;
}

export type Program = Module | Script;

export interface Module extends Node, HasSpan, HasInterpreter {
  type: "Module";

  body: ModuleItem[];
}

export interface Script extends Node, HasSpan, HasInterpreter {
  type: "Script";

  body: Statement[];
}

export type ModuleItem = ModuleDeclaration | Statement;

export type BinaryOperator =
  | "=="
  | "!="
  | "==="
  | "!=="
  | "<"
  | "<="
  | ">"
  | ">="
  | "<<"
  | ">>"
  | ">>>"
  | "+"
  | "-"
  | "*"
  | "/"
  | "%"
  | "|"
  | "^"
  | "&"
  | "||"
  | "&&"
  | "in"
  | "instanceof"
  | "**"
  | "??";

export type AssignmentOperator =
  | "="
  | "+="
  | "-="
  | "*="
  | "/="
  | "%="
  | "<<="
  | ">>="
  | ">>>="
  | "|="
  | "^="
  | "&="
  | "**="
  | "&&="
  | "||="
  | "??=";

export type UpdateOperator = "++" | "--";

export type UnaryOperator =
  | "-"
  | "+"
  | "!"
  | "~"
  | "typeof"
  | "void"
  | "delete";

export type Pattern =
  | BindingIdentifier
  | ArrayPattern
  | RestElement
  | ObjectPattern
  | AssignmentPattern
  | Invalid
  | Expression;

export interface BindingIdentifier extends PatternBase {
  type: "Identifier";
  value: string;
  optional: boolean;
}

export interface ArrayPattern extends PatternBase {
  type: "ArrayPattern";

  elements: (Pattern | undefined)[];

  optional: boolean;
}

export interface ObjectPattern extends PatternBase {
  type: "ObjectPattern";

  properties: ObjectPatternProperty[];

  optional: boolean;
}

export interface AssignmentPattern extends PatternBase {
  type: "AssignmentPattern";

  left: Pattern;
  right: Expression;
}

export interface RestElement extends PatternBase {
  type: "RestElement";

  rest: Span;

  argument: Pattern;
}

export type ObjectPatternProperty =
  | KeyValuePatternProperty
  | AssignmentPatternProperty
  | RestElement;

/**
 * `{key: value}`
 */
export interface KeyValuePatternProperty extends Node {
  type: "KeyValuePatternProperty";

  key: PropertyName;
  value: Pattern;
}

/**
 * `{key}` or `{key = value}`
 */
export interface AssignmentPatternProperty extends Node, HasSpan {
  type: "AssignmentPatternProperty";

  key: Identifier;
  value?: Expression;
}

/** Identifier is `a` in `{ a, }` */
export type Property =
  | Identifier
  | KeyValueProperty
  | AssignmentProperty
  | GetterProperty
  | SetterProperty
  | MethodProperty;

interface PropBase extends Node {
  key: PropertyName;
}

export interface KeyValueProperty extends PropBase {
  type: "KeyValueProperty";

  value: Expression;
}

export interface AssignmentProperty extends Node {
  type: "AssignmentProperty";

  key: Identifier;
  value: Expression;
}

export interface GetterProperty extends PropBase, HasSpan {
  type: "GetterProperty";

  typeAnnotation?: TsTypeAnnotation;

  body?: BlockStatement;
}

export interface SetterProperty extends PropBase, HasSpan {
  type: "SetterProperty";

  param: Pattern;
  body?: BlockStatement;
}

export interface MethodProperty extends PropBase, Fn {
  type: "MethodProperty";
}

export type PropertyName =
  | Identifier
  | StringLiteral
  | NumericLiteral
  | ComputedPropName
  | BigIntLiteral;

export interface ComputedPropName extends Node, HasSpan {
  type: "Computed";
  expression: Expression;
}

export interface BlockStatement extends Node, HasSpan {
  type: "BlockStatement";

  stmts: Statement[];
}

export interface ExpressionStatement extends Node, HasSpan {
  type: "ExpressionStatement";
  expression: Expression;
}

export type Statement =
  | BlockStatement
  | EmptyStatement
  | DebuggerStatement
  | WithStatement
  | ReturnStatement
  | LabeledStatement
  | BreakStatement
  | ContinueStatement
  | IfStatement
  | SwitchStatement
  | ThrowStatement
  | TryStatement
  | WhileStatement
  | DoWhileStatement
  | ForStatement
  | ForInStatement
  | ForOfStatement
  | Declaration
  | ExpressionStatement;

export interface EmptyStatement extends Node, HasSpan {
  type: "EmptyStatement";
}

export interface DebuggerStatement extends Node, HasSpan {
  type: "DebuggerStatement";
}

export interface WithStatement extends Node, HasSpan {
  type: "WithStatement";

  object: Expression;
  body: Statement;
}

export interface ReturnStatement extends Node, HasSpan {
  type: "ReturnStatement";

  argument?: Expression;
}

export interface LabeledStatement extends Node, HasSpan {
  type: "LabeledStatement";

  label: Identifier;
  body: Statement;
}

export interface BreakStatement extends Node, HasSpan {
  type: "BreakStatement";

  label?: Identifier;
}

export interface ContinueStatement extends Node, HasSpan {
  type: "ContinueStatement";

  label?: Identifier;
}

export interface IfStatement extends Node, HasSpan {
  type: "IfStatement";

  test: Expression;
  consequent: Statement;
  alternate?: Statement;
}

export interface SwitchStatement extends Node, HasSpan {
  type: "SwitchStatement";

  discriminant: Expression;
  cases: SwitchCase[];
}

export interface ThrowStatement extends Node, HasSpan {
  type: "ThrowStatement";

  argument: Expression;
}

export interface TryStatement extends Node, HasSpan {
  type: "TryStatement";

  block: BlockStatement;
  handler?: CatchClause;
  finalizer?: BlockStatement;
}

export interface WhileStatement extends Node, HasSpan {
  type: "WhileStatement";

  test: Expression;
  body: Statement;
}

export interface DoWhileStatement extends Node, HasSpan {
  type: "DoWhileStatement";

  test: Expression;
  body: Statement;
}

export interface ForStatement extends Node, HasSpan {
  type: "ForStatement";

  init?: VariableDeclaration | Expression;
  test?: Expression;
  update?: Expression;
  body: Statement;
}

export interface ForInStatement extends Node, HasSpan {
  type: "ForInStatement";

  left: VariableDeclaration | Pattern;
  right: Expression;
  body: Statement;
}

export interface ForOfStatement extends Node, HasSpan {
  type: "ForOfStatement";

  /**
   *  Span of the await token.
   *
   *  es2018 for-await-of statements, e.g., `for await (const x of xs) {`
   */
  await?: Span;
  left: VariableDeclaration | Pattern;
  right: Expression;
  body: Statement;
}

export interface SwitchCase extends Node, HasSpan {
  type: "SwitchCase";

  /**
   * Undefined for default case
   */
  test?: Expression;
  consequent: Statement[];
}

export interface CatchClause extends Node, HasSpan {
  type: "CatchClause";

  /**
   * The param is `undefined` if the catch binding is omitted. E.g., `try { foo() } catch {}`
   */
  param?: Pattern;
  body: BlockStatement;
}

export interface TsTypeAnnotation extends Node, HasSpan {
  type: "TsTypeAnnotation";

  typeAnnotation: TsType;
}

export interface TsTypeParameterDeclaration extends Node, HasSpan {
  type: "TsTypeParameterDeclaration";

  parameters: TsTypeParameter[];
}

export interface TsTypeParameter extends Node, HasSpan {
  type: "TsTypeParameter";

  name: Identifier;
  in: boolean;
  out: boolean;
  constraint?: TsType;
  default?: TsType;
}

export interface TsTypeParameterInstantiation extends Node, HasSpan {
  type: "TsTypeParameterInstantiation";

  params: TsType[];
}

export interface TsParameterProperty extends Node, HasSpan, HasDecorator {
  type: "TsParameterProperty";

  accessibility?: Accessibility;
  override: boolean;
  readonly: boolean;
  param: TsParameterPropertyParameter;
}

export type TsParameterPropertyParameter =
  | BindingIdentifier
  | AssignmentPattern;

export interface TsQualifiedName extends Node {
  type: "TsQualifiedName";

  left: TsEntityName;
  right: Identifier;
}

export type TsEntityName = TsQualifiedName | Identifier;

export type TsTypeElement =
  | TsCallSignatureDeclaration
  | TsConstructSignatureDeclaration
  | TsPropertySignature
  | TsGetterSignature
  | TsSetterSignature
  | TsMethodSignature
  | TsIndexSignature;

export interface TsCallSignatureDeclaration extends Node, HasSpan {
  type: "TsCallSignatureDeclaration";

  params: TsFnParameter[];
  typeAnnotation?: TsTypeAnnotation;
  typeParams?: TsTypeParameterDeclaration;
}

export interface TsConstructSignatureDeclaration extends Node, HasSpan {
  type: "TsConstructSignatureDeclaration";

  params: TsFnParameter[];
  typeAnnotation?: TsTypeAnnotation;
  typeParams?: TsTypeParameterDeclaration;
}

export interface TsPropertySignature extends Node, HasSpan {
  type: "TsPropertySignature";

  readonly: boolean;
  key: Expression;
  computed: boolean;
  optional: boolean;

  init?: Expression;
  params: TsFnParameter[];

  typeAnnotation?: TsTypeAnnotation;
  typeParams?: TsTypeParameterDeclaration;
}

export interface TsGetterSignature extends Node, HasSpan {
  type: "TsGetterSignature";

  readonly: boolean;
  key: Expression;
  computed: boolean;
  optional: boolean;
  typeAnnotation?: TsTypeAnnotation;
}

export interface TsSetterSignature extends Node, HasSpan {
  type: "TsSetterSignature";

  readonly: boolean;
  key: Expression;
  computed: boolean;
  optional: boolean;
  param: TsFnParameter;
}

export interface TsMethodSignature extends Node, HasSpan {
  type: "TsMethodSignature";

  readonly: boolean;
  key: Expression;
  computed: boolean;
  optional: boolean;
  params: TsFnParameter[];

  typeAnn?: TsTypeAnnotation;
  typeParams?: TsTypeParameterDeclaration;
}

export interface TsIndexSignature extends Node, HasSpan {
  type: "TsIndexSignature";

  params: TsFnParameter[];

  typeAnnotation?: TsTypeAnnotation;

  readonly: boolean;
  static: boolean;
}

export type TsType =
  | TsKeywordType
  | TsThisType
  | TsFnOrConstructorType
  | TsTypeReference
  | TsTypeQuery
  | TsTypeLiteral
  | TsArrayType
  | TsTupleType
  | TsOptionalType
  | TsRestType
  | TsUnionOrIntersectionType
  | TsConditionalType
  | TsInferType
  | TsParenthesizedType
  | TsTypeOperator
  | TsIndexedAccessType
  | TsMappedType
  | TsLiteralType
  | TsTypePredicate
  | TsImportType;

export type TsFnOrConstructorType = TsFunctionType | TsConstructorType;

export interface TsKeywordType extends Node, HasSpan {
  type: "TsKeywordType";

  kind: TsKeywordTypeKind;
}

export type TsKeywordTypeKind =
  | "any"
  | "unknown"
  | "number"
  | "object"
  | "boolean"
  | "bigint"
  | "string"
  | "symbol"
  | "void"
  | "undefined"
  | "null"
  | "never"
  | "intrinsic";

export interface TsThisType extends Node, HasSpan {
  type: "TsThisType";
}

export type TsFnParameter =
  | BindingIdentifier
  | ArrayPattern
  | RestElement
  | ObjectPattern;

export interface TsFunctionType extends Node, HasSpan {
  type: "TsFunctionType";

  params: TsFnParameter[];

  typeParams?: TsTypeParameterDeclaration;
  typeAnnotation: TsTypeAnnotation;
}

export interface TsConstructorType extends Node, HasSpan {
  type: "TsConstructorType";

  params: TsFnParameter[];

  typeParams?: TsTypeParameterDeclaration;
  typeAnnotation: TsTypeAnnotation;
  isAbstract: boolean;
}

export interface TsTypeReference extends Node, HasSpan {
  type: "TsTypeReference";

  typeName: TsEntityName;
  typeParams?: TsTypeParameterInstantiation;
}

export interface TsTypePredicate extends Node, HasSpan {
  type: "TsTypePredicate";

  asserts: boolean;

  paramName: TsThisTypeOrIdent;
  typeAnnotation?: TsTypeAnnotation;
}

export type TsThisTypeOrIdent = TsThisType | Identifier;

export interface TsImportType extends Node, HasSpan {
  type: "TsImportType";

  argument: StringLiteral;
  qualifier?: TsEntityName;
  typeArguments?: TsTypeParameterInstantiation;
}

/**
 * `typeof` operator
 */
export interface TsTypeQuery extends Node, HasSpan {
  type: "TsTypeQuery";

  exprName: TsTypeQueryExpr;
  typeArguments?: TsTypeParameterInstantiation;
}

export type TsTypeQueryExpr = TsEntityName | TsImportType;

export interface TsTypeLiteral extends Node, HasSpan {
  type: "TsTypeLiteral";

  members: TsTypeElement[];
}

export interface TsArrayType extends Node, HasSpan {
  type: "TsArrayType";

  elemType: TsType;
}

export interface TsTupleType extends Node, HasSpan {
  type: "TsTupleType";

  elemTypes: TsTupleElement[];
}

export interface TsTupleElement extends Node, HasSpan {
  type: "TsTupleElement";

  label?: Pattern;
  ty: TsType;
}

export interface TsOptionalType extends Node, HasSpan {
  type: "TsOptionalType";

  typeAnnotation: TsType;
}

export interface TsRestType extends Node, HasSpan {
  type: "TsRestType";

  typeAnnotation: TsType;
}

export type TsUnionOrIntersectionType = TsUnionType | TsIntersectionType;

export interface TsUnionType extends Node, HasSpan {
  type: "TsUnionType";

  types: TsType[];
}

export interface TsIntersectionType extends Node, HasSpan {
  type: "TsIntersectionType";

  types: TsType[];
}

export interface TsConditionalType extends Node, HasSpan {
  type: "TsConditionalType";

  checkType: TsType;
  extendsType: TsType;
  trueType: TsType;
  falseType: TsType;
}

export interface TsInferType extends Node, HasSpan {
  type: "TsInferType";

  typeParam: TsTypeParameter;
}

export interface TsParenthesizedType extends Node, HasSpan {
  type: "TsParenthesizedType";

  typeAnnotation: TsType;
}

export interface TsTypeOperator extends Node, HasSpan {
  type: "TsTypeOperator";

  op: TsTypeOperatorOp;
  typeAnnotation: TsType;
}

export type TsTypeOperatorOp = "keyof" | "unique" | "readonly";

export interface TsIndexedAccessType extends Node, HasSpan {
  type: "TsIndexedAccessType";

  readonly: boolean;
  objectType: TsType;
  indexType: TsType;
}

export type TruePlusMinus = true | "+" | "-";

export interface TsMappedType extends Node, HasSpan {
  type: "TsMappedType";

  readonly?: TruePlusMinus;
  typeParam: TsTypeParameter;
  nameType?: TsType;
  optional?: TruePlusMinus;
  typeAnnotation?: TsType;
}

export interface TsLiteralType extends Node, HasSpan {
  type: "TsLiteralType";

  literal: TsLiteral;
}

export type TsLiteral =
  | NumericLiteral
  | StringLiteral
  | BooleanLiteral
  | BigIntLiteral
  | TsTemplateLiteralType;

export interface TsTemplateLiteralType extends Node, HasSpan {
  type: "TemplateLiteral";
  types: TsType[];
  quasis: TemplateElement[];
}

// // ================
// // TypeScript declarations
// // ================

export interface TsInterfaceDeclaration extends Node, HasSpan {
  type: "TsInterfaceDeclaration";

  id: Identifier;
  declare: boolean;
  typeParams?: TsTypeParameterDeclaration;
  extends: TsExpressionWithTypeArguments[];
  body: TsInterfaceBody;
}

export interface TsInterfaceBody extends Node, HasSpan {
  type: "TsInterfaceBody";

  body: TsTypeElement[];
}

export interface TsExpressionWithTypeArguments extends Node, HasSpan {
  type: "TsExpressionWithTypeArguments";

  expression: Expression;
  typeArguments?: TsTypeParameterInstantiation;
}

export interface TsTypeAliasDeclaration extends Node, HasSpan {
  type: "TsTypeAliasDeclaration";

  declare: boolean;
  id: Identifier;
  typeParams?: TsTypeParameterDeclaration;
  typeAnnotation: TsType;
}

export interface TsEnumDeclaration extends Node, HasSpan {
  type: "TsEnumDeclaration";

  declare: boolean;
  isConst: boolean;
  id: Identifier;
  members: TsEnumMember[];
}

export interface TsEnumMember extends Node, HasSpan {
  type: "TsEnumMember";

  id: TsEnumMemberId;
  init?: Expression;
}

export type TsEnumMemberId = Identifier | StringLiteral;

export interface TsModuleDeclaration extends Node, HasSpan {
  type: "TsModuleDeclaration";

  declare: boolean;
  global: boolean;
  id: TsModuleName;
  body?: TsNamespaceBody;
}

/**
 * `namespace A.B { }` is a namespace named `A` with another TsNamespaceDecl as its body.
 */
export type TsNamespaceBody = TsModuleBlock | TsNamespaceDeclaration;

export interface TsModuleBlock extends Node, HasSpan {
  type: "TsModuleBlock";

  body: ModuleItem[];
}

export interface TsNamespaceDeclaration extends Node, HasSpan {
  type: "TsNamespaceDeclaration";

  declare: boolean;
  global: boolean;
  id: Identifier;
  body: TsNamespaceBody;
}

export type TsModuleName = Identifier | StringLiteral;

export interface TsImportEqualsDeclaration extends Node, HasSpan {
  type: "TsImportEqualsDeclaration";

  declare: boolean;
  isExport: boolean;
  isTypeOnly: boolean;
  id: Identifier;
  moduleRef: TsModuleReference;
}

export type TsModuleReference = TsEntityName | TsExternalModuleReference;

export interface TsExternalModuleReference extends Node, HasSpan {
  type: "TsExternalModuleReference";

  expression: StringLiteral;
}

export interface TsExportAssignment extends Node, HasSpan {
  type: "TsExportAssignment";

  expression: Expression;
}

export interface TsNamespaceExportDeclaration extends Node, HasSpan {
  type: "TsNamespaceExportDeclaration";

  id: Identifier;
}

export interface TsAsExpression extends ExpressionBase {
  type: "TsAsExpression";

  expression: Expression;
  typeAnnotation: TsType;
}

export interface TsInstantiation extends Node, HasSpan {
  type: "TsInstantiation";

  expression: Expression;
  typeArguments: TsTypeParameterInstantiation;
}

export interface TsTypeAssertion extends ExpressionBase {
  type: "TsTypeAssertion";

  expression: Expression;
  typeAnnotation: TsType;
}

export interface TsConstAssertion extends ExpressionBase {
  type: "TsConstAssertion";

  expression: Expression;
}

export interface TsNonNullExpression extends ExpressionBase {
  type: "TsNonNullExpression";

  expression: Expression;
}

export type Accessibility = "public" | "protected" | "private";

export interface Invalid extends Node, HasSpan {
  type: "Invalid";
}



export function minify(src: string, opts?: JsMinifyOptions): Promise<Output>;
export function minifySync(code: string, opts?: JsMinifyOptions): Output;

export function parse(src: string, options: ParseOptions & {
    isModule: false;
}): Promise<Script>;
export function parse(src: string, options?: ParseOptions): Promise<Module>;
export function parseSync(src: string, options: ParseOptions & {
    isModule: false;
}): Script;
export function parseSync(src: string, options?: ParseOptions): Module;

export function print(m: Program, options?: Options): Promise<Output>;
export function printSync(m: Program, options?: Options): Output

/**
 * Note: this interface currently does not do _actual_ async work, only provides
 * a corresponding async interfaces to the `@swc/core`'s interface.
 */
export function transform(
    code: string | Program,
    options?: Options,
    experimental_plugin_bytes_resolver?: any
): Promise<Output>;
/**
 * @param {string} code
 * @param {Options} opts
 * @param {Record<string, ArrayBuffer>} experimental_plugin_bytes_resolver An object contains bytes array for the plugin
 * specified in config. Key of record represents the name of the plugin specified in config. Note this is an experimental
 * interface, likely will change.
 * @returns {Output}
 */
export function transformSync(code: string | Program, opts?: Options, experimental_plugin_bytes_resolver?: any): Output;


