// Type definitions for source-map 0.7
// Project: https://github.com/mozilla/source-map
// Definitions by: Morten Houston Ludvigsen <https://github.com/MortenHoustonLudvigsen>,
//                 Ron Buckton <https://github.com/rbuckton>,
//                 John Vilk <https://github.com/jvilk>
// Definitions: https://github.com/mozilla/source-map
export type SourceMapUrl = string;

export interface StartOfSourceMap {
  file?: string;
  sourceRoot?: string;
  skipValidation?: boolean;
}

export interface RawSourceMap {
  version: number;
  sources: string[];
  names: string[];
  sourceRoot?: string;
  sourcesContent?: string[];
  mappings: string;
  file: string;
}

export interface RawIndexMap extends StartOfSourceMap {
  version: number;
  sections: RawSection[];
}

export interface RawSection {
  offset: Position;
  map: RawSourceMap;
}

export interface Position {
  line: number;
  column: number;
}

export interface NullablePosition {
  line: number | null;
  column: number | null;
  lastColumn: number | null;
}

export interface MappedPosition {
  source: string;
  line: number;
  column: number;
  name?: string;
}

export interface NullableMappedPosition {
  source: string | null;
  line: number | null;
  column: number | null;
  name: string | null;
}

export interface MappingItem {
  source: string;
  generatedLine: number;
  generatedColumn: number;
  lastGeneratedColumn: number | null;
  originalLine: number;
  originalColumn: number;
  name: string;
}

export interface Mapping {
  generated: Position;
  original: Position;
  source: string;
  name?: string;
}

export interface CodeWithSourceMap {
  code: string;
  map: SourceMapGenerator;
}

export interface SourceMappings {
  "lib/mappings.wasm": SourceMapUrl | ArrayBuffer;
}

export interface SourceMapConsumer {
  /**
   * When using SourceMapConsumer outside of node.js, for example on the Web, it
   * needs to know from what URL to load lib/mappings.wasm. You must inform it
   * by calling initialize before constructing any SourceMapConsumers.
   *
   * @param mappings an object with the following property:
   *   - "lib/mappings.wasm": A String containing the URL of the
   *     lib/mappings.wasm file, or an ArrayBuffer with the contents of
   *     lib/mappings.wasm.
   */
  initialize(mappings: SourceMappings): void;

  /**
   * Compute the last column for each generated mapping. The last column is
   * inclusive.
   */
  computeColumnSpans(): void;

  /**
   * Returns the original source, line, and column information for the generated
   * source's line and column positions provided. The only argument is an object
   * with the following properties:
   *
   *   - line: The line number in the generated source.
   *   - column: The column number in the generated source.
   *   - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
   *     'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
   *     closest element that is smaller than or greater than the one we are
   *     searching for, respectively, if the exact element cannot be found.
   *     Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
   *
   * and an object is returned with the following properties:
   *
   *   - source: The original source file, or null.
   *   - line: The line number in the original source, or null.
   *   - column: The column number in the original source, or null.
   *   - name: The original identifier, or null.
   */
  originalPositionFor(
    generatedPosition: Position & { bias?: number }
  ): NullableMappedPosition;

  /**
   * Returns the generated line and column information for the original source,
   * line, and column positions provided. The only argument is an object with
   * the following properties:
   *
   *   - source: The filename of the original source.
   *   - line: The line number in the original source.
   *   - column: The column number in the original source.
   *   - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
   *     'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
   *     closest element that is smaller than or greater than the one we are
   *     searching for, respectively, if the exact element cannot be found.
   *     Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
   *
   * and an object is returned with the following properties:
   *
   *   - line: The line number in the generated source, or null.
   *   - column: The column number in the generated source, or null.
   */
  generatedPositionFor(
    originalPosition: MappedPosition & { bias?: number }
  ): NullablePosition;

  /**
   * Returns all generated line and column information for the original source,
   * line, and column provided. If no column is provided, returns all mappings
   * corresponding to a either the line we are searching for or the next
   * closest line that has any mappings. Otherwise, returns all mappings
   * corresponding to the given line and either the column we are searching for
   * or the next closest column that has any offsets.
   *
   * The only argument is an object with the following properties:
   *
   *   - source: The filename of the original source.
   *   - line: The line number in the original source.
   *   - column: Optional. the column number in the original source.
   *
   * and an array of objects is returned, each with the following properties:
   *
   *   - line: The line number in the generated source, or null.
   *   - column: The column number in the generated source, or null.
   */
  allGeneratedPositionsFor(
    originalPosition: MappedPosition
  ): NullablePosition[];

  /**
   * Return true if we have the source content for every source in the source
   * map, false otherwise.
   */
  hasContentsOfAllSources(): boolean;

  /**
   * Returns the original source content. The only argument is the url of the
   * original source file. Returns null if no original source content is
   * available.
   */
  sourceContentFor(
    source: string,
    returnNullOnMissing?: boolean
  ): string | null;

  /**
   * Iterate over each mapping between an original source/line/column and a
   * generated line/column in this source map.
   *
   * @param callback
   *        The function that is called with each mapping.
   * @param context
   *        Optional. If specified, this object will be the value of `this` every
   *        time that `aCallback` is called.
   * @param order
   *        Either `SourceMapConsumer.GENERATED_ORDER` or
   *        `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
   *        iterate over the mappings sorted by the generated file's line/column
   *        order or the original's source/line/column order, respectively. Defaults to
   *        `SourceMapConsumer.GENERATED_ORDER`.
   */
  eachMapping(
    callback: (mapping: MappingItem) => void,
    context?: any,
    order?: number
  ): void;
  /**
   * Free this source map consumer's associated wasm data that is manually-managed.
   * Alternatively, you can use SourceMapConsumer.with to avoid needing to remember to call destroy.
   */
  destroy(): void;
}

export interface SourceMapConsumerConstructor {
  prototype: SourceMapConsumer;

  GENERATED_ORDER: number;
  ORIGINAL_ORDER: number;
  GREATEST_LOWER_BOUND: number;
  LEAST_UPPER_BOUND: number;

  new (
    rawSourceMap: RawSourceMap,
    sourceMapUrl?: SourceMapUrl
  ): Promise<BasicSourceMapConsumer>;
  new (
    rawSourceMap: RawIndexMap,
    sourceMapUrl?: SourceMapUrl
  ): Promise<IndexedSourceMapConsumer>;
  new (
    rawSourceMap: RawSourceMap | RawIndexMap | string,
    sourceMapUrl?: SourceMapUrl
  ): Promise<BasicSourceMapConsumer | IndexedSourceMapConsumer>;

  /**
   * Create a BasicSourceMapConsumer from a SourceMapGenerator.
   *
   * @param sourceMap
   *        The source map that will be consumed.
   */
  fromSourceMap(
    sourceMap: SourceMapGenerator,
    sourceMapUrl?: SourceMapUrl
  ): Promise<BasicSourceMapConsumer>;

  /**
   * Construct a new `SourceMapConsumer` from `rawSourceMap` and `sourceMapUrl`
   * (see the `SourceMapConsumer` constructor for details. Then, invoke the `async
   * function f(SourceMapConsumer) -> T` with the newly constructed consumer, wait
   * for `f` to complete, call `destroy` on the consumer, and return `f`'s return
   * value.
   *
   * You must not use the consumer after `f` completes!
   *
   * By using `with`, you do not have to remember to manually call `destroy` on
   * the consumer, since it will be called automatically once `f` completes.
   *
   * ```js
   * const xSquared = await SourceMapConsumer.with(
   *   myRawSourceMap,
   *   null,
   *   async function (consumer) {
   *     // Use `consumer` inside here and don't worry about remembering
   *     // to call `destroy`.
   *
   *     const x = await whatever(consumer);
   *     return x * x;
   *   }
   * );
   *
   * // You may not use that `consumer` anymore out here; it has
   * // been destroyed. But you can use `xSquared`.
   * console.log(xSquared);
   * ```
   */
  with<T>(
    rawSourceMap: RawSourceMap | RawIndexMap | string,
    sourceMapUrl: SourceMapUrl | null | undefined,
    callback: (
      consumer: BasicSourceMapConsumer | IndexedSourceMapConsumer
    ) => Promise<T> | T
  ): Promise<T>;
}

export const SourceMapConsumer: SourceMapConsumerConstructor;

export interface BasicSourceMapConsumer extends SourceMapConsumer {
  file: string;
  sourceRoot: string;
  sources: string[];
  sourcesContent: string[];
}

export interface BasicSourceMapConsumerConstructor {
  prototype: BasicSourceMapConsumer;

  new (rawSourceMap: RawSourceMap | string): Promise<BasicSourceMapConsumer>;

  /**
   * Create a BasicSourceMapConsumer from a SourceMapGenerator.
   *
   * @param sourceMap
   *        The source map that will be consumed.
   */
  fromSourceMap(sourceMap: SourceMapGenerator): Promise<BasicSourceMapConsumer>;
}

export const BasicSourceMapConsumer: BasicSourceMapConsumerConstructor;

export interface IndexedSourceMapConsumer extends SourceMapConsumer {
  sources: string[];
}

export interface IndexedSourceMapConsumerConstructor {
  prototype: IndexedSourceMapConsumer;

  new (rawSourceMap: RawIndexMap | string): Promise<IndexedSourceMapConsumer>;
}

export const IndexedSourceMapConsumer: IndexedSourceMapConsumerConstructor;

export class SourceMapGenerator {
  constructor(startOfSourceMap?: StartOfSourceMap);

  /**
   * Creates a new SourceMapGenerator based on a SourceMapConsumer
   *
   * @param sourceMapConsumer The SourceMap.
   */
  static fromSourceMap(
    sourceMapConsumer: SourceMapConsumer
  ): SourceMapGenerator;

  /**
   * Add a single mapping from original source line and column to the generated
   * source's line and column for this source map being created. The mapping
   * object should have the following properties:
   *
   *   - generated: An object with the generated line and column positions.
   *   - original: An object with the original line and column positions.
   *   - source: The original source file (relative to the sourceRoot).
   *   - name: An optional original token name for this mapping.
   */
  addMapping(mapping: Mapping): void;

  /**
   * Set the source content for a source file.
   */
  setSourceContent(sourceFile: string, sourceContent: string): void;

  /**
   * Applies the mappings of a sub-source-map for a specific source file to the
   * source map being generated. Each mapping to the supplied source file is
   * rewritten using the supplied source map. Note: The resolution for the
   * resulting mappings is the minimium of this map and the supplied map.
   *
   * @param sourceMapConsumer The source map to be applied.
   * @param sourceFile Optional. The filename of the source file.
   *        If omitted, SourceMapConsumer's file property will be used.
   * @param sourceMapPath Optional. The dirname of the path to the source map
   *        to be applied. If relative, it is relative to the SourceMapConsumer.
   *        This parameter is needed when the two source maps aren't in the same
   *        directory, and the source map to be applied contains relative source
   *        paths. If so, those relative source paths need to be rewritten
   *        relative to the SourceMapGenerator.
   */
  applySourceMap(
    sourceMapConsumer: SourceMapConsumer,
    sourceFile?: string,
    sourceMapPath?: string
  ): void;

  toString(): string;

  toJSON(): RawSourceMap;
}

export class SourceNode {
  children: SourceNode[];
  sourceContents: any;
  line: number;
  column: number;
  source: string;
  name: string;

  constructor();
  constructor(
    line: number | null,
    column: number | null,
    source: string | null,
    chunks?: Array<string | SourceNode> | SourceNode | string,
    name?: string
  );

  static fromStringWithSourceMap(
    code: string,
    sourceMapConsumer: SourceMapConsumer,
    relativePath?: string
  ): SourceNode;

  add(chunk: Array<string | SourceNode> | SourceNode | string): SourceNode;

  prepend(chunk: Array<string | SourceNode> | SourceNode | string): SourceNode;

  setSourceContent(sourceFile: string, sourceContent: string): void;

  walk(fn: (chunk: string, mapping: MappedPosition) => void): void;

  walkSourceContents(fn: (file: string, content: string) => void): void;

  join(sep: string): SourceNode;

  replaceRight(pattern: string, replacement: string): SourceNode;

  toString(): string;

  toStringWithSourceMap(startOfSourceMap?: StartOfSourceMap): CodeWithSourceMap;
}
