<commit_before>import {ListWrapper} from '../../src/facade/collection';
import {stringify, isBlank} from '../../src/facade/lang';
import {BaseException, WrappedException} from '../../src/facade/exceptions';
import {ReflectiveKey} from './reflective_key';
import {ReflectiveInjector} from './reflective_injector';

function findFirstClosedCycle(keys: any[]): any[] {
  var res = [];
  for (var i = 0; i < keys.length; ++i) {
    if (ListWrapper.contains(res, keys[i])) {
      res.push(keys[i]);
      return res;
    } else {
      res.push(keys[i]);
    }
  }
  return res;
}

function constructResolvingPath(keys: any[]): string {
  if (keys.length > 1) {
    var reversed = findFirstClosedCycle(ListWrapper.reversed(keys));
    var tokenStrs = reversed.map(k => stringify(k.token));
    return " (" + tokenStrs.join(' -> ') + ")";
  } else {
    return "";
  }
}


/**
 * Base class for all errors arising from misconfigured providers.
 */
export class AbstractProviderError extends BaseException {
  /** @internal */
  message: string;

  /** @internal */
  keys: ReflectiveKey[];

  /** @internal */
  injectors: ReflectiveInjector[];

  /** @internal */
  constructResolvingMessage: Function;

  constructor(injector: ReflectiveInjector, key: ReflectiveKey,
              constructResolvingMessage: Function) {
    super("DI Exception");
    this.keys = [key];
    this.injectors = [injector];
    this.constructResolvingMessage = constructResolvingMessage;
    this.message = this.constructResolvingMessage(this.keys);
  }

  addKey(injector: ReflectiveInjector, key: ReflectiveKey): void {
    this.injectors.push(injector);
    this.keys.push(key);
    this.message = this.constructResolvingMessage(this.keys);
  }

  get context() { return this.injectors[this.injectors.length - 1].debugContext(); }
}

/**
 * Thrown when trying to retrieve a dependency by `Key` from {@link Injector}, but the
 * {@link Injector} does not have a {@link Provider} for {@link Key}.
 *
 * ### Example ([live demo](http://plnkr.co/edit/vq8D3FRB9aGbnWJqtEPE?p=preview))
 *
 * ```typescript
 * class A {
 *   constructor(b:B) {}
 * }
 *
 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
 * ```
 */
export class NoProviderError extends AbstractProviderError {
  constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
    super(injector, key, function(keys: any[]) {
      var first = stringify(ListWrapper.first(keys).token);
      return `No provider for ${first}!${constructResolvingPath(keys)}`;
    });
  }
}

/**
 * Thrown when dependencies form a cycle.
 *
 * ### Example ([live demo](http://plnkr.co/edit/wYQdNos0Tzql3ei1EV9j?p=info))
 *
 * ```typescript
 * var injector = Injector.resolveAndCreate([
 *   provide("one", {useFactory: (two) => "two", deps: [[new Inject("two")]]}),
 *   provide("two", {useFactory: (one) => "one", deps: [[new Inject("one")]]})
 * ]);
 *
 * expect(() => injector.get("one")).toThrowError();
 * ```
 *
 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
 */
export class CyclicDependencyError extends AbstractProviderError {
  constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
    super(injector, key, function(keys: any[]) {
      return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
    });
  }
}

/**
 * Thrown when a constructing type returns with an Error.
 *
 * The `InstantiationError` class contains the original error plus the dependency graph which caused
 * this object to be instantiated.
 *
 * ### Example ([live demo](http://plnkr.co/edit/7aWYdcqTQsP0eNqEdUAf?p=preview))
 *
 * ```typescript
 * class A {
 *   constructor() {
 *     throw new Error('message');
 *   }
 * }
 *
 * var injector = Injector.resolveAndCreate([A]);

 * try {
 *   injector.get(A);
 * } catch (e) {
 *   expect(e instanceof InstantiationError).toBe(true);
 *   expect(e.originalException.message).toEqual("message");
 *   expect(e.originalStack).toBeDefined();
 * }
 * ```
 */
export class InstantiationError extends WrappedException {
  /** @internal */
  keys: ReflectiveKey[];

  /** @internal */
  injectors: ReflectiveInjector[];

  constructor(injector: ReflectiveInjector, originalException, originalStack, key: ReflectiveKey) {
    super("DI Exception", originalException, originalStack, null);
    this.keys = [key];
    this.injectors = [injector];
  }

  addKey(injector: ReflectiveInjector, key: ReflectiveKey): void {
    this.injectors.push(injector);
    this.keys.push(key);
  }

  get wrapperMessage(): string {
    var first = stringify(ListWrapper.first(this.keys).token);
    return `Error during instantiation of ${first}!${constructResolvingPath(this.keys)}.`;
  }

  get causeKey(): ReflectiveKey { return this.keys[0]; }

  get context() { return this.injectors[this.injectors.length - 1].debugContext(); }
}

/**
 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
 * creation.
 *
 * ### Example ([live demo](http://plnkr.co/edit/YatCFbPAMCL0JSSQ4mvH?p=preview))
 *
 * ```typescript
 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
 * ```
 */
export class InvalidProviderError extends BaseException {
  constructor(provider) {
    super("Invalid provider - only instances of Provider and Type are allowed, got: " +
          provider.toString());
  }
}

/**
 * Thrown when the class has no annotation information.
 *
 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
 * need to be injected into the constructor.
 *
 * ### Example ([live demo](http://plnkr.co/edit/rHnZtlNS7vJOPQ6pcVkm?p=preview))
 *
 * ```typescript<commit_msg>fix(di): type error in InvalidProviderError<commit_after>import {ListWrapper} from '../../src/facade/collection';
import {stringify, isBlank} from '../../src/facade/lang';
import {BaseException, WrappedException} from '../../src/facade/exceptions';
import {ReflectiveKey} from './reflective_key';
import {ReflectiveInjector} from './reflective_injector';

function findFirstClosedCycle(keys: any[]): any[] {
  var res = [];
  for (var i = 0; i < keys.length; ++i) {
    if (ListWrapper.contains(res, keys[i])) {
      res.push(keys[i]);
      return res;
    } else {
      res.push(keys[i]);
    }
  }
  return res;
}

function constructResolvingPath(keys: any[]): string {
  if (keys.length > 1) {
    var reversed = findFirstClosedCycle(ListWrapper.reversed(keys));
    var tokenStrs = reversed.map(k => stringify(k.token));
    return " (" + tokenStrs.join(' -> ') + ")";
  } else {
    return "";
  }
}


/**
 * Base class for all errors arising from misconfigured providers.
 */
export class AbstractProviderError extends BaseException {
  /** @internal */
  message: string;

  /** @internal */
  keys: ReflectiveKey[];

  /** @internal */
  injectors: ReflectiveInjector[];

  /** @internal */
  constructResolvingMessage: Function;

  constructor(injector: ReflectiveInjector, key: ReflectiveKey,
              constructResolvingMessage: Function) {
    super("DI Exception");
    this.keys = [key];
    this.injectors = [injector];
    this.constructResolvingMessage = constructResolvingMessage;
    this.message = this.constructResolvingMessage(this.keys);
  }

  addKey(injector: ReflectiveInjector, key: ReflectiveKey): void {
    this.injectors.push(injector);
    this.keys.push(key);
    this.message = this.constructResolvingMessage(this.keys);
  }

  get context() { return this.injectors[this.injectors.length - 1].debugContext(); }
}

/**
 * Thrown when trying to retrieve a dependency by `Key` from {@link Injector}, but the
 * {@link Injector} does not have a {@link Provider} for {@link Key}.
 *
 * ### Example ([live demo](http://plnkr.co/edit/vq8D3FRB9aGbnWJqtEPE?p=preview))
 *
 * ```typescript
 * class A {
 *   constructor(b:B) {}
 * }
 *
 * expect(() => Injector.resolveAndCreate([A])).toThrowError();
 * ```
 */
export class NoProviderError extends AbstractProviderError {
  constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
    super(injector, key, function(keys: any[]) {
      var first = stringify(ListWrapper.first(keys).token);
      return `No provider for ${first}!${constructResolvingPath(keys)}`;
    });
  }
}

/**
 * Thrown when dependencies form a cycle.
 *
 * ### Example ([live demo](http://plnkr.co/edit/wYQdNos0Tzql3ei1EV9j?p=info))
 *
 * ```typescript
 * var injector = Injector.resolveAndCreate([
 *   provide("one", {useFactory: (two) => "two", deps: [[new Inject("two")]]}),
 *   provide("two", {useFactory: (one) => "one", deps: [[new Inject("one")]]})
 * ]);
 *
 * expect(() => injector.get("one")).toThrowError();
 * ```
 *
 * Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
 */
export class CyclicDependencyError extends AbstractProviderError {
  constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
    super(injector, key, function(keys: any[]) {
      return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
    });
  }
}

/**
 * Thrown when a constructing type returns with an Error.
 *
 * The `InstantiationError` class contains the original error plus the dependency graph which caused
 * this object to be instantiated.
 *
 * ### Example ([live demo](http://plnkr.co/edit/7aWYdcqTQsP0eNqEdUAf?p=preview))
 *
 * ```typescript
 * class A {
 *   constructor() {
 *     throw new Error('message');
 *   }
 * }
 *
 * var injector = Injector.resolveAndCreate([A]);

 * try {
 *   injector.get(A);
 * } catch (e) {
 *   expect(e instanceof InstantiationError).toBe(true);
 *   expect(e.originalException.message).toEqual("message");
 *   expect(e.originalStack).toBeDefined();
 * }
 * ```
 */
export class InstantiationError extends WrappedException {
  /** @internal */
  keys: ReflectiveKey[];

  /** @internal */
  injectors: ReflectiveInjector[];

  constructor(injector: ReflectiveInjector, originalException, originalStack, key: ReflectiveKey) {
    super("DI Exception", originalException, originalStack, null);
    this.keys = [key];
    this.injectors = [injector];
  }

  addKey(injector: ReflectiveInjector, key: ReflectiveKey): void {
    this.injectors.push(injector);
    this.keys.push(key);
  }

  get wrapperMessage(): string {
    var first = stringify(ListWrapper.first(this.keys).token);
    return `Error during instantiation of ${first}!${constructResolvingPath(this.keys)}.`;
  }

  get causeKey(): ReflectiveKey { return this.keys[0]; }

  get context() { return this.injectors[this.injectors.length - 1].debugContext(); }
}

/**
 * Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
 * creation.
 *
 * ### Example ([live demo](http://plnkr.co/edit/YatCFbPAMCL0JSSQ4mvH?p=preview))
 *
 * ```typescript
 * expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
 * ```
 */
export class InvalidProviderError extends BaseException {
  constructor(provider) {
    super(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
  }
}

/**
 * Thrown when the class has no annotation information.
 *
 * Lack of annotation information prevents the {@link Injector} from determining which dependencies
 * need to be injected into the constructor.
 *
 * ### Example ([live demo](http://plnkr.co/edit/rHnZtlNS7vJOPQ6pcVkm?p=preview))
 *
 * ```typescript
{'fraction_non_alphanumeric': 0.15642262165716792, 'fraction_numerical': 0.003156510302498904, 'mean_word_length': 4.128597122302159, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1212332', 'n_tokens_mistral': 3664, 'n_tokens_neox': 3638, 'n_words': 831}