text: /**
   * @license
   * Copyright Google Inc. All Rights Reserved.
   *
   * Use of this source code is governed by an MIT-style license that can be
   * found in the LICENSE file at https://angular.io/license
   */
  import { global, isPresent, stringify } from '../facade/lang';
  import { Type, isType } from '../type';
  /**
   * Attention: This regex has to hold even if the code is minified!
   */
  export var /** @type {?} */ DELEGATE_CTOR = /^function\s+\S+\(\)\s*{\s*("use strict";)?\s*(return\s+)?\S+\.apply\(this,\s*arguments\)/;
  export var ReflectionCapabilities = (function () {
      /**
       * @param {?=} reflect
       */
      function ReflectionCapabilities(reflect) {
          this._reflect = reflect || global.Reflect;
      }
      /**
       * @return {?}
       */
      ReflectionCapabilities.prototype.isReflectionEnabled = function () { return true; };
      /**
       * @param {?} t
       * @return {?}
       */
      ReflectionCapabilities.prototype.factory = function (t) { return function () {
          var args = [];
          for (var _i = 0; _i < arguments.length; _i++) {
              args[_i - 0] = arguments[_i];
          }
          return new (t.bind.apply(t, [void 0].concat(args)))();
      }; };
      /**
       * \@internal
       * @param {?} paramTypes
       * @param {?} paramAnnotations
       * @return {?}
       */
      ReflectionCapabilities.prototype._zipTypesAndAnnotations = function (paramTypes, paramAnnotations) {
          var /** @type {?} */ result;
          if (typeof paramTypes === 'undefined') {
              result = new Array(paramAnnotations.length);
          }
          else {
              result = new Array(paramTypes.length);
          }
          for (var /** @type {?} */ i = 0; i < result.length; i++) {
              // TS outputs Object for parameters without types, while Traceur omits
              // the annotations. For now we preserve the Traceur behavior to aid
              // migration, but this can be revisited.
              if (typeof paramTypes === 'undefined') {
                  result[i] = [];
              }
              else if (paramTypes[i] != Object) {
                  result[i] = [paramTypes[i]];
              }
              else {
                  result[i] = [];
              }
              if (paramAnnotations && isPresent(paramAnnotations[i])) {
                  result[i] = result[i].concat(paramAnnotations[i]);
              }
          }
          return result;
      };
      /**
       * @param {?} type
       * @param {?} parentCtor
       * @return {?}
       */
      ReflectionCapabilities.prototype._ownParameters = function (type, parentCtor) {
          // If we have no decorators, we only have function.length as metadata.
          // In that case, to detect whether a child class declared an own constructor or not,
          // we need to look inside of that constructor to check whether it is
          // just calling the parent.
          // This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
          // that sets 'design:paramtypes' to []
          // if a class inherits from another class but has no ctor declared itself.
          if (DELEGATE_CTOR.exec(type.toString())) {
              return null;
          }
          // Prefer the direct API.
          if (((type)).parameters && ((type)).parameters !== parentCtor.parameters) {
              return ((type)).parameters;
          }
          // API of tsickle for lowering decorators to properties on the class.
          var /** @type {?} */ tsickleCtorParams = ((type)).ctorParameters;
          if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
              // Newer tsickle uses a function closure
              // Retain the non-function case for compatibility with older tsickle
              var /** @type {?} */ ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
              var /** @type {?} */ paramTypes = ctorParameters.map(function (ctorParam) { return ctorParam && ctorParam.type; });
              var /** @type {?} */ paramAnnotations = ctorParameters.map(function (ctorParam) {
                  return ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators);
              });
              return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
          }
          // API for metadata created by invoking the decorators.
          if (isPresent(this._reflect) && isPresent(this._reflect.getOwnMetadata)) {
              var /** @type {?} */ paramAnnotations = this._reflect.getOwnMetadata('parameters', type);
              var /** @type {?} */ paramTypes = this._reflect.getOwnMetadata('design:paramtypes', type);
              if (paramTypes || paramAnnotations) {
                  return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
              }
          }
          // If a class has no decorators, at least create metadata
          // based on function.length.
          // Note: We know that this is a real constructor as we checked
          // the content of the constructor above.
          return new Array(((type.length))).fill(undefined);
      };
      /**
       * @param {?} type
       * @return {?}
       */
      ReflectionCapabilities.prototype.parameters = function (type) {
          // Note: only report metadata if we have at least one class decorator
          // to stay in sync with the static reflector.
          if (!isType(type)) {
              return [];
          }
          var /** @type {?} */ parentCtor = getParentCtor(type);
          var /** @type {?} */ parameters = this._ownParameters(type, parentCtor);
          if (!parameters && parentCtor !== Object) {
              parameters = this.parameters(parentCtor);
          }
          return parameters || [];
      };
      /**
       * @param {?} typeOrFunc
       * @param {?} parentCtor
       * @return {?}
       */
      ReflectionCapabilities.prototype._ownAnnotations = function (typeOrFunc, parentCtor) {
          // Prefer the direct API.
          if (((typeOrFunc)).annotations && ((typeOrFunc)).annotations !== parentCtor.annotations) {
              var /** @type {?} */ annotations = ((typeOrFunc)).annotations;
              if (typeof annotations === 'function' && annotations.annotations) {
                  annotations = annotations.annotations;
              }
              return annotations;
          }
          // API of tsickle for lowering decorators to properties on the class.
          if (((typeOrFunc)).decorators && ((typeOrFunc)).decorators !== parentCtor.decorators) {
              return convertTsickleDecoratorIntoMetadata(((typeOrFunc)).decorators);
          }
          // API for metadata created by invoking the decorators.
          if (this._reflect && this._reflect.getOwnMetadata) {
              return this._reflect.getOwnMetadata('annotations', typeOrFunc);
          }
      };
      /**
       * @param {?} typeOrFunc
       * @return {?}
       */
      ReflectionCapabilities.prototype.annotations = function (typeOrFunc) {
          if (!isType(typeOrFunc)) {
              return [];
          }
          var /** @type {?} */ parentCtor = getParentCtor(typeOrFunc);
          var /** @type {?} */ ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
          var /** @type {?} */ parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
          return parentAnnotations.concat(ownAnnotations);
      };
      /**
       * @param {?} typeOrFunc
       * @param {?} parentCtor
       * @return {?}
       */
      ReflectionCapabilities.prototype._ownPropMetadata = function (typeOrFunc, parentCtor) {
          // Prefer the direct API.
          if (((typeOrFunc)).propMetadata &&
              ((typeOrFunc)).propMetadata !== parentCtor.propMetadata) {
              var /** @type {?} */ propMetadata = ((typeOrFunc)).propMetadata;
              if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
                  propMetadata = propMetadata.propMetadata;
              }
              return propMetadata;
          }
          // API of tsickle for lowering decorators to properties on the class.
          if (((typeOrFunc)).propDecorators &&
              ((typeOrFunc)).propDecorators !== parentCtor.propDecorators) {
              var /** @type {?} */ propDecorators_1 = ((typeOrFunc)).propDecorators;
              var /** @type {?} */ propMetadata_1 = ({});
              Object.keys(propDecorators_1).forEach(function (prop) {
                  propMetadata_1[prop] = convertTsickleDecoratorIntoMetadata(propDecorators_1[prop]);
              });
              return propMetadata_1;
          }
          // API for metadata created by invoking the decorators.
          if (this._reflect && this._reflect.getOwnMetadata) {
              return this._reflect.getOwnMetadata('propMetadata', typeOrFunc);
          }
      };
      /**
       * @param {?} typeOrFunc
       * @return {?}
       */
      ReflectionCapabilities.prototype.propMetadata = function (typeOrFunc) {
          if (!isType(typeOrFunc)) {
              return {};
          }
          var /** @type {?} */ parentCtor = getParentCtor(typeOrFunc);
          var /** @type {?} */ propMetadata = {};
          if (parentCtor !== Object) {
              var /** @type {?} */ parentPropMetadata_1 = this.propMetadata(parentCtor);
              Object.keys(parentPropMetadata_1).forEach(function (propName) {
                  propMetadata[propName] = parentPropMetadata_1[propName];
              });
          }
          var /** @type {?} */ ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
          if (ownPropMetadata) {
              Object.keys(ownPropMetadata).forEach(function (propName) {
                  var /** @type {?} */ decorators = [];
                  if (propMetadata.hasOwnProperty(propName)) {
                      decorators.push.apply(decorators, propMetadata[propName]);
                  }
                  decorators.push.apply(decorators, ownPropMetadata[propName]);
                  propMetadata[propName] = decorators;
              });
          }
          return propMetadata;
      };
      /**
       * @param {?} type
       * @param {?} lcProperty
       * @return {?}
       */
      ReflectionCapabilities.prototype.hasLifecycleHook = function (type, lcProperty) {
          return type instanceof Type && lcProperty in type.prototype;
      };
      /**
       * @param {?} name
       * @return {?}
       */
      ReflectionCapabilities.prototype.getter = function (name) { return ((new Function('o', 'return o.' + name + ';'))); };
      /**
       * @param {?} name
       * @return {?}
       */
      ReflectionCapabilities.prototype.setter = function (name) {
          return ((new Function('o', 'v', 'return o.' + name + ' = v;')));
      };
      /**
       * @param {?} name
       * @return {?}
       */
      ReflectionCapabilities.prototype.method = function (name) {
          var /** @type {?} */ functionBody = "if (!o." + name + ") throw new Error('\"" + name + "\" is undefined');\n        return o." + name + ".apply(o, args);";
          return ((new Function('o', 'args', functionBody)));
      };
      /**
       * @param {?} type
       * @return {?}
       */
      ReflectionCapabilities.prototype.importUri = function (type) {
          // StaticSymbol
          if (typeof type === 'object' && type['filePath']) {
              return type['filePath'];
          }
          // Runtime type
          return "./" + stringify(type);
      };
      /**
       * @param {?} name
       * @param {?} moduleUrl
       * @param {?} runtime
       * @return {?}
       */
      ReflectionCapabilities.prototype.resolveIdentifier = function (name, moduleUrl, runtime) { return runtime; };
      /**
       * @param {?} enumIdentifier
       * @param {?} name
       * @return {?}
       */
      ReflectionCapabilities.prototype.resolveEnum = function (enumIdentifier, name) { return enumIdentifier[name]; };
      return ReflectionCapabilities;
  }());
  function ReflectionCapabilities_tsickle_Closure_declarations() {
      /** @type {?} */
      ReflectionCapabilities.prototype._reflect;
  }
  /**
   * @param {?} decoratorInvocations
   * @return {?}
   */
  function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
      if (!decoratorInvocations) {
          return [];
      }
      return decoratorInvocations.map(function (decoratorInvocation) {
          var /** @type {?} */ decoratorType = decoratorInvocation.type;
          var /** @type {?} */ annotationCls = decoratorType.annotationCls;
          var /** @type {?} */ annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
          return new (annotationCls.bind.apply(annotationCls, [void 0].concat(annotationArgs)))();
      });
  }
  /**
   * @param {?} ctor
   * @return {?}
   */
  function getParentCtor(ctor) {
      var /** @type {?} */ parentProto = Object.getPrototypeOf(ctor.prototype);
      var /** @type {?} */ parentCtor = parentProto ? parentProto.constructor : null;
      // Note: We always use `Object` as the null value
      // to simplify checking later on.
      return parentCtor || Object;
  }
  //# sourceMappingURL=reflection_capabilities.js.map