Igor Minar 5d3ba8dec7 test: update ts-api-guardian's strip_export_pattern to exclude Ivy instructions (#38224)
Previously the instructions were included in the golden files to monitor the frequency and rate of
the instruction API changes for the purpose of understanding the stability of this API (as it was
considered for becoming a public API and deployed to npm via generated code).

This experiment has confirmed that the instruction API is not stable enough to be used as public
API. We've since also came up with an alternative plan to compile libraries with the Ivy compiler
for npm deployment and this plan does not rely on making Ivy instructions public.

For these reasons, I'm removing the instructions from the golden files as it's no longer important
to track them.

The are three instructions that are still being included: `ɵɵdefineInjectable`, `ɵɵinject`, and
`ɵɵInjectableDef`.

These instructions are already generated by the VE compiler to support tree-shakable providers, and
code depending on these instructions is already deployed to npm. For this reason we need to treat
them as public api.

This change also reduces the code review overhead, because changes to public api golden files now
require multiple approvals.

PR Close #38224
2020-07-27 14:37:41 -07:00

287 lines
11 KiB
TypeScript

/**
* @license
* Copyright Google LLC 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 {Type} from '../../interface/type';
import {getClosureSafeProperty} from '../../util/property';
import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, ValueProvider} from './provider';
/**
* Information about how a type or `InjectionToken` interfaces with the DI system.
*
* At a minimum, this includes a `factory` which defines how to create the given type `T`, possibly
* requesting injection of other types if necessary.
*
* Optionally, a `providedIn` parameter specifies that the given type belongs to a particular
* `InjectorDef`, `NgModule`, or a special scope (e.g. `'root'`). A value of `null` indicates
* that the injectable does not belong to any scope.
*
* @codeGenApi
* @publicApi The ViewEngine compiler emits code with this type for injectables. This code is
* deployed to npm, and should be treated as public api.
*/
export interface ɵɵInjectableDef<T> {
/**
* Specifies that the given type belongs to a particular injector:
* - `InjectorType` such as `NgModule`,
* - `'root'` the root injector
* - `'any'` all injectors.
* - `null`, does not belong to any injector. Must be explicitly listed in the injector
* `providers`.
*/
providedIn: InjectorType<any>|'root'|'platform'|'any'|null;
/**
* The token to which this definition belongs.
*
* Note that this may not be the same as the type that the `factory` will create.
*/
token: unknown;
/**
* Factory method to execute to create an instance of the injectable.
*/
factory: (t?: Type<any>) => T;
/**
* In a case of no explicit injector, a location where the instance of the injectable is stored.
*/
value: T|undefined;
}
/**
* Information about the providers to be included in an `Injector` as well as how the given type
* which carries the information should be created by the DI system.
*
* An `InjectorDef` can import other types which have `InjectorDefs`, forming a deep nested
* structure of providers with a defined priority (identically to how `NgModule`s also have
* an import/dependency structure).
*
* NOTE: This is a private type and should not be exported
*
* @codeGenApi
*/
export interface ɵɵInjectorDef<T> {
factory: () => T;
// TODO(alxhub): Narrow down the type here once decorators properly change the return type of the
// class they are decorating (to add the ɵprov property for example).
providers: (Type<any>|ValueProvider|ExistingProvider|FactoryProvider|ConstructorProvider|
StaticClassProvider|ClassProvider|any[])[];
imports: (InjectorType<any>|InjectorTypeWithProviders<any>)[];
}
/**
* A `Type` which has an `InjectableDef` static field.
*
* `InjectableDefType`s contain their own Dependency Injection metadata and are usable in an
* `InjectorDef`-based `StaticInjector.
*
* @publicApi
*/
export interface InjectableType<T> extends Type<T> {
/**
* Opaque type whose structure is highly version dependent. Do not rely on any properties.
*/
ɵprov: never;
}
/**
* A type which has an `InjectorDef` static field.
*
* `InjectorDefTypes` can be used to configure a `StaticInjector`.
*
* @publicApi
*/
export interface InjectorType<T> extends Type<T> {
/**
* Opaque type whose structure is highly version dependent. Do not rely on any properties.
*/
ɵinj: never;
}
/**
* Describes the `InjectorDef` equivalent of a `ModuleWithProviders`, an `InjectorDefType` with an
* associated array of providers.
*
* Objects of this type can be listed in the imports section of an `InjectorDef`.
*
* NOTE: This is a private type and should not be exported
*/
export interface InjectorTypeWithProviders<T> {
ngModule: InjectorType<T>;
providers?: (Type<any>|ValueProvider|ExistingProvider|FactoryProvider|ConstructorProvider|
StaticClassProvider|ClassProvider|any[])[];
}
/**
* Construct an `InjectableDef` which defines how a token will be constructed by the DI system, and
* in which injectors (if any) it will be available.
*
* This should be assigned to a static `ɵprov` field on a type, which will then be an
* `InjectableType`.
*
* Options:
* * `providedIn` determines which injectors will include the injectable, by either associating it
* with an `@NgModule` or other `InjectorType`, or by specifying that this injectable should be
* provided in the `'root'` injector, which will be the application-level injector in most apps.
* * `factory` gives the zero argument function which will create an instance of the injectable.
* The factory can call `inject` to access the `Injector` and request injection of dependencies.
*
* @codeGenApi
* @publicApi This instruction has been emitted by ViewEngine for some time and is deployed to npm.
*/
export function ɵɵdefineInjectable<T>(opts: {
token: unknown,
providedIn?: Type<any>|'root'|'platform'|'any'|null, factory: () => T,
}): never {
return ({
token: opts.token,
providedIn: opts.providedIn as any || null,
factory: opts.factory,
value: undefined,
} as ɵɵInjectableDef<T>) as never;
}
/**
* @deprecated in v8, delete after v10. This API should be used only be generated code, and that
* code should now use ɵɵdefineInjectable instead.
* @publicApi
*/
export const defineInjectable = ɵɵdefineInjectable;
/**
* Construct an `InjectorDef` which configures an injector.
*
* This should be assigned to a static injector def (`ɵinj`) field on a type, which will then be an
* `InjectorType`.
*
* Options:
*
* * `factory`: an `InjectorType` is an instantiable type, so a zero argument `factory` function to
* create the type must be provided. If that factory function needs to inject arguments, it can
* use the `inject` function.
* * `providers`: an optional array of providers to add to the injector. Each provider must
* either have a factory or point to a type which has a `ɵprov` static property (the
* type must be an `InjectableType`).
* * `imports`: an optional array of imports of other `InjectorType`s or `InjectorTypeWithModule`s
* whose providers will also be added to the injector. Locally provided types will override
* providers from imports.
*
* @codeGenApi
*/
export function ɵɵdefineInjector(options: {factory: () => any, providers?: any[], imports?: any[]}):
never {
return ({
factory: options.factory,
providers: options.providers || [],
imports: options.imports || [],
} as ɵɵInjectorDef<any>) as never;
}
/**
* Read the injectable def (`ɵprov`) for `type` in a way which is immune to accidentally reading
* inherited value.
*
* @param type A type which may have its own (non-inherited) `ɵprov`.
*/
export function getInjectableDef<T>(type: any): ɵɵInjectableDef<T>|null {
return getOwnDefinition(type, type[NG_PROV_DEF]) ||
getOwnDefinition(type, type[NG_INJECTABLE_DEF]);
}
/**
* Return `def` only if it is defined directly on `type` and is not inherited from a base
* class of `type`.
*
* The function `Object.hasOwnProperty` is not sufficient to distinguish this case because in older
* browsers (e.g. IE10) static property inheritance is implemented by copying the properties.
*
* Instead, the definition's `token` is compared to the `type`, and if they don't match then the
* property was not defined directly on the type itself, and was likely inherited. The definition
* is only returned if the `type` matches the `def.token`.
*/
function getOwnDefinition<T>(type: any, def: ɵɵInjectableDef<T>): ɵɵInjectableDef<T>|null {
return def && def.token === type ? def : null;
}
/**
* Read the injectable def (`ɵprov`) for `type` or read the `ɵprov` from one of its ancestors.
*
* @param type A type which may have `ɵprov`, via inheritance.
*
* @deprecated Will be removed in a future version of Angular, where an error will occur in the
* scenario if we find the `ɵprov` on an ancestor only.
*/
export function getInheritedInjectableDef<T>(type: any): ɵɵInjectableDef<T>|null {
// See `jit/injectable.ts#compileInjectable` for context on NG_PROV_DEF_FALLBACK.
const def = type &&
(type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF] ||
(type[NG_PROV_DEF_FALLBACK] && type[NG_PROV_DEF_FALLBACK]()));
if (def) {
const typeName = getTypeName(type);
// TODO(FW-1307): Re-add ngDevMode when closure can handle it
// ngDevMode &&
console.warn(
`DEPRECATED: DI is instantiating a token "${
typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` +
`This will become an error in a future version of Angular. Please add @Injectable() to the "${
typeName}" class.`);
return def;
} else {
return null;
}
}
/** Gets the name of a type, accounting for some cross-browser differences. */
function getTypeName(type: any): string {
// `Function.prototype.name` behaves differently between IE and other browsers. In most browsers
// it'll always return the name of the function itself, no matter how many other functions it
// inherits from. On IE the function doesn't have its own `name` property, but it takes it from
// the lowest level in the prototype chain. E.g. if we have `class Foo extends Parent` most
// browsers will evaluate `Foo.name` to `Foo` while IE will return `Parent`. We work around
// the issue by converting the function to a string and parsing its name out that way via a regex.
if (type.hasOwnProperty('name')) {
return type.name;
}
const match = ('' + type).match(/^function\s*([^\s(]+)/);
return match === null ? '' : match[1];
}
/**
* Read the injector def type in a way which is immune to accidentally reading inherited value.
*
* @param type type which may have an injector def (`ɵinj`)
*/
export function getInjectorDef<T>(type: any): ɵɵInjectorDef<T>|null {
return type && (type.hasOwnProperty(NG_INJ_DEF) || type.hasOwnProperty(NG_INJECTOR_DEF)) ?
(type as any)[NG_INJ_DEF] :
null;
}
export const NG_PROV_DEF = getClosureSafeProperty({ɵprov: getClosureSafeProperty});
export const NG_INJ_DEF = getClosureSafeProperty({ɵinj: getClosureSafeProperty});
// On IE10 properties defined via `defineProperty` won't be inherited by child classes,
// which will break inheriting the injectable definition from a grandparent through an
// undecorated parent class. We work around it by defining a fallback method which will be
// used to retrieve the definition. This should only be a problem in JIT mode, because in
// AOT TypeScript seems to have a workaround for static properties. When inheriting from an
// undecorated parent is no longer supported in v10, this can safely be removed.
export const NG_PROV_DEF_FALLBACK = getClosureSafeProperty({ɵprovFallback: getClosureSafeProperty});
// We need to keep these around so we can read off old defs if new defs are unavailable
export const NG_INJECTABLE_DEF = getClosureSafeProperty({ngInjectableDef: getClosureSafeProperty});
export const NG_INJECTOR_DEF = getClosureSafeProperty({ngInjectorDef: getClosureSafeProperty});