perf: Don’t subclass Error; resulting in smaller binary (#14160)
Subclassing errors is problematic since Error returns a new instance. All of the patching which we do than prevent proper application of source maps. PR Close #14160
This commit is contained in:

committed by
Miško Hevery

parent
3c2842be96
commit
c33fda2607
@ -20,7 +20,7 @@ import * as constants from './change_detection/constants';
|
||||
import * as console from './console';
|
||||
import * as debug from './debug/debug_renderer';
|
||||
import * as reflective_provider from './di/reflective_provider';
|
||||
import {ComponentStillLoadingError} from './linker/compiler';
|
||||
import {ERROR_COMPONENT_TYPE} from './errors';
|
||||
import * as component_factory from './linker/component_factory';
|
||||
import * as component_factory_resolver from './linker/component_factory_resolver';
|
||||
import * as debug_context from './linker/debug_context';
|
||||
@ -104,12 +104,11 @@ export const __core_private__: {
|
||||
DEFAULT_STATE: typeof DEFAULT_STATE_,
|
||||
EMPTY_STATE: typeof EMPTY_STATE_,
|
||||
FILL_STYLE_FLAG: typeof FILL_STYLE_FLAG_,
|
||||
_ComponentStillLoadingError?: ComponentStillLoadingError,
|
||||
ComponentStillLoadingError: typeof ComponentStillLoadingError,
|
||||
isPromise: typeof isPromise,
|
||||
isObservable: typeof isObservable,
|
||||
AnimationTransition: typeof AnimationTransition
|
||||
view_utils: typeof view_utils,
|
||||
ERROR_COMPONENT_TYPE: typeof ERROR_COMPONENT_TYPE,
|
||||
} = {
|
||||
isDefaultChangeDetectionStrategy: constants.isDefaultChangeDetectionStrategy,
|
||||
ChangeDetectorStatus: constants.ChangeDetectorStatus,
|
||||
@ -156,8 +155,8 @@ export const __core_private__: {
|
||||
DEFAULT_STATE: DEFAULT_STATE_,
|
||||
EMPTY_STATE: EMPTY_STATE_,
|
||||
FILL_STYLE_FLAG: FILL_STYLE_FLAG_,
|
||||
ComponentStillLoadingError: ComponentStillLoadingError,
|
||||
isPromise: isPromise,
|
||||
isObservable: isObservable,
|
||||
AnimationTransition: AnimationTransition
|
||||
AnimationTransition: AnimationTransition,
|
||||
ERROR_COMPONENT_TYPE: ERROR_COMPONENT_TYPE
|
||||
};
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {BaseError, WrappedError} from '../facade/errors';
|
||||
import {wrappedError} from '../error_handler';
|
||||
import {ERROR_ORIGINAL_ERROR, getOriginalError} from '../errors';
|
||||
import {stringify} from '../facade/lang';
|
||||
import {Type} from '../type';
|
||||
|
||||
@ -35,38 +36,31 @@ function constructResolvingPath(keys: any[]): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for all errors arising from misconfigured providers.
|
||||
* @stable
|
||||
*/
|
||||
export class AbstractProviderError extends BaseError {
|
||||
/** @internal */
|
||||
message: string;
|
||||
|
||||
/** @internal */
|
||||
export interface InjectionError extends Error {
|
||||
keys: ReflectiveKey[];
|
||||
|
||||
/** @internal */
|
||||
injectors: ReflectiveInjector[];
|
||||
constructResolvingMessage: (this: InjectionError) => string;
|
||||
addKey(injector: ReflectiveInjector, key: ReflectiveKey): void;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
constructResolvingMessage: Function;
|
||||
function injectionError(
|
||||
injector: ReflectiveInjector, key: ReflectiveKey,
|
||||
constructResolvingMessage: (this: InjectionError) => string,
|
||||
originalError?: Error): InjectionError {
|
||||
const error = (originalError ? wrappedError('', originalError) : Error()) as InjectionError;
|
||||
error.addKey = addKey;
|
||||
error.keys = [key];
|
||||
error.injectors = [injector];
|
||||
error.constructResolvingMessage = constructResolvingMessage;
|
||||
error.message = error.constructResolvingMessage();
|
||||
(error as any)[ERROR_ORIGINAL_ERROR] = originalError;
|
||||
return error;
|
||||
}
|
||||
|
||||
constructor(
|
||||
injector: ReflectiveInjector, key: ReflectiveKey, constructResolvingMessage: Function) {
|
||||
super('DI Error');
|
||||
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);
|
||||
}
|
||||
function addKey(this: InjectionError, injector: ReflectiveInjector, key: ReflectiveKey): void {
|
||||
this.injectors.push(injector);
|
||||
this.keys.push(key);
|
||||
this.message = this.constructResolvingMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,15 +76,12 @@ export class AbstractProviderError extends BaseError {
|
||||
*
|
||||
* expect(() => Injector.resolveAndCreate([A])).toThrowError();
|
||||
* ```
|
||||
* @stable
|
||||
*/
|
||||
export class NoProviderError extends AbstractProviderError {
|
||||
constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
|
||||
super(injector, key, function(keys: any[]) {
|
||||
const first = stringify(keys[0].token);
|
||||
return `No provider for ${first}!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
export function noProviderError(injector: ReflectiveInjector, key: ReflectiveKey): InjectionError {
|
||||
return injectionError(injector, key, function(this: InjectionError) {
|
||||
const first = stringify(this.keys[0].token);
|
||||
return `No provider for ${first}!${constructResolvingPath(this.keys)}`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,14 +99,12 @@ export class NoProviderError extends AbstractProviderError {
|
||||
* ```
|
||||
*
|
||||
* Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
|
||||
* @stable
|
||||
*/
|
||||
export class CyclicDependencyError extends AbstractProviderError {
|
||||
constructor(injector: ReflectiveInjector, key: ReflectiveKey) {
|
||||
super(injector, key, function(keys: any[]) {
|
||||
return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
export function cyclicDependencyError(
|
||||
injector: ReflectiveInjector, key: ReflectiveKey): InjectionError {
|
||||
return injectionError(injector, key, function(this: InjectionError) {
|
||||
return `Cannot instantiate cyclic dependency!${constructResolvingPath(this.keys)}`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,34 +132,14 @@ export class CyclicDependencyError extends AbstractProviderError {
|
||||
* expect(e.originalStack).toBeDefined();
|
||||
* }
|
||||
* ```
|
||||
* @stable
|
||||
*/
|
||||
export class InstantiationError extends WrappedError {
|
||||
/** @internal */
|
||||
keys: ReflectiveKey[];
|
||||
|
||||
/** @internal */
|
||||
injectors: ReflectiveInjector[];
|
||||
|
||||
constructor(
|
||||
injector: ReflectiveInjector, originalException: any, originalStack: any,
|
||||
key: ReflectiveKey) {
|
||||
super('DI Error', originalException);
|
||||
this.keys = [key];
|
||||
this.injectors = [injector];
|
||||
}
|
||||
|
||||
addKey(injector: ReflectiveInjector, key: ReflectiveKey): void {
|
||||
this.injectors.push(injector);
|
||||
this.keys.push(key);
|
||||
}
|
||||
|
||||
get message(): string {
|
||||
export function instantiationError(
|
||||
injector: ReflectiveInjector, originalException: any, originalStack: any,
|
||||
key: ReflectiveKey): InjectionError {
|
||||
return injectionError(injector, key, function(this: InjectionError) {
|
||||
const first = stringify(this.keys[0].token);
|
||||
return `${this.originalError.message}: Error during instantiation of ${first}!${constructResolvingPath(this.keys)}.`;
|
||||
}
|
||||
|
||||
get causeKey(): ReflectiveKey { return this.keys[0]; }
|
||||
return `${getOriginalError(this).message}: Error during instantiation of ${first}!${constructResolvingPath(this.keys)}.`;
|
||||
}, originalException);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,12 +151,10 @@ export class InstantiationError extends WrappedError {
|
||||
* ```typescript
|
||||
* expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
|
||||
* ```
|
||||
* @stable
|
||||
*/
|
||||
export class InvalidProviderError extends BaseError {
|
||||
constructor(provider: any) {
|
||||
super(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
|
||||
}
|
||||
export function invalidProviderError(provider: any) {
|
||||
return Error(
|
||||
`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,26 +186,21 @@ export class InvalidProviderError extends BaseError {
|
||||
* ```
|
||||
* @stable
|
||||
*/
|
||||
export class NoAnnotationError extends BaseError {
|
||||
constructor(typeOrFunc: Type<any>|Function, params: any[][]) {
|
||||
super(NoAnnotationError._genMessage(typeOrFunc, params));
|
||||
}
|
||||
|
||||
private static _genMessage(typeOrFunc: Type<any>|Function, params: any[][]) {
|
||||
const signature: string[] = [];
|
||||
for (let i = 0, ii = params.length; i < ii; i++) {
|
||||
const parameter = params[i];
|
||||
if (!parameter || parameter.length == 0) {
|
||||
signature.push('?');
|
||||
} else {
|
||||
signature.push(parameter.map(stringify).join(' '));
|
||||
}
|
||||
export function noAnnotationError(typeOrFunc: Type<any>| Function, params: any[][]): Error {
|
||||
const signature: string[] = [];
|
||||
for (let i = 0, ii = params.length; i < ii; i++) {
|
||||
const parameter = params[i];
|
||||
if (!parameter || parameter.length == 0) {
|
||||
signature.push('?');
|
||||
} else {
|
||||
signature.push(parameter.map(stringify).join(' '));
|
||||
}
|
||||
return 'Cannot resolve all parameters for \'' + stringify(typeOrFunc) + '\'(' +
|
||||
signature.join(', ') + '). ' +
|
||||
'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
|
||||
stringify(typeOrFunc) + '\' is decorated with Injectable.';
|
||||
}
|
||||
return Error(
|
||||
'Cannot resolve all parameters for \'' + stringify(typeOrFunc) + '\'(' +
|
||||
signature.join(', ') + '). ' +
|
||||
'Make sure that all the parameters are decorated with Inject or have valid type annotations and that \'' +
|
||||
stringify(typeOrFunc) + '\' is decorated with Injectable.');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,8 +217,8 @@ export class NoAnnotationError extends BaseError {
|
||||
* ```
|
||||
* @stable
|
||||
*/
|
||||
export class OutOfBoundsError extends BaseError {
|
||||
constructor(index: number) { super(`Index ${index} is out-of-bounds.`); }
|
||||
export function outOfBoundsError(index: number) {
|
||||
return Error(`Index ${index} is out-of-bounds.`);
|
||||
}
|
||||
|
||||
// TODO: add a working example after alpha38 is released
|
||||
@ -272,10 +234,7 @@ export class OutOfBoundsError extends BaseError {
|
||||
* ])).toThrowError();
|
||||
* ```
|
||||
*/
|
||||
export class MixingMultiProvidersWithRegularProvidersError extends BaseError {
|
||||
constructor(provider1: any, provider2: any) {
|
||||
super(
|
||||
'Cannot mix multi providers and regular providers, got: ' + provider1.toString() + ' ' +
|
||||
provider2.toString());
|
||||
}
|
||||
export function mixingMultiProvidersWithRegularProvidersError(
|
||||
provider1: any, provider2: any): Error {
|
||||
return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
import {Injector, THROW_IF_NOT_FOUND} from './injector';
|
||||
import {Self, SkipSelf} from './metadata';
|
||||
import {Provider} from './provider';
|
||||
import {AbstractProviderError, CyclicDependencyError, InstantiationError, NoProviderError, OutOfBoundsError} from './reflective_errors';
|
||||
import {cyclicDependencyError, instantiationError, noProviderError, outOfBoundsError} from './reflective_errors';
|
||||
import {ReflectiveKey} from './reflective_key';
|
||||
import {ReflectiveDependency, ResolvedReflectiveFactory, ResolvedReflectiveProvider, resolveReflectiveProviders} from './reflective_provider';
|
||||
|
||||
@ -331,7 +331,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
|
||||
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
|
||||
if (index < 0 || index >= this._providers.length) {
|
||||
throw new OutOfBoundsError(index);
|
||||
throw outOfBoundsError(index);
|
||||
}
|
||||
return this._providers[index];
|
||||
}
|
||||
@ -339,7 +339,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
/** @internal */
|
||||
_new(provider: ResolvedReflectiveProvider): any {
|
||||
if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
|
||||
throw new CyclicDependencyError(this, provider.key);
|
||||
throw cyclicDependencyError(this, provider.key);
|
||||
}
|
||||
return this._instantiateProvider(provider);
|
||||
}
|
||||
@ -368,7 +368,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
deps =
|
||||
ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
|
||||
} catch (e) {
|
||||
if (e instanceof AbstractProviderError || e instanceof InstantiationError) {
|
||||
if (e.addKey) {
|
||||
e.addKey(this, provider.key);
|
||||
}
|
||||
throw e;
|
||||
@ -378,7 +378,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
try {
|
||||
obj = factory(...deps);
|
||||
} catch (e) {
|
||||
throw new InstantiationError(this, e, e.stack, provider.key);
|
||||
throw instantiationError(this, e, e.stack, provider.key);
|
||||
}
|
||||
|
||||
return obj;
|
||||
@ -420,7 +420,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
||||
if (notFoundValue !== THROW_IF_NOT_FOUND) {
|
||||
return notFoundValue;
|
||||
} else {
|
||||
throw new NoProviderError(this, key);
|
||||
throw noProviderError(this, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import {Type} from '../type';
|
||||
import {resolveForwardRef} from './forward_ref';
|
||||
import {Host, Inject, Optional, Self, SkipSelf} from './metadata';
|
||||
import {ClassProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ValueProvider} from './provider';
|
||||
import {InvalidProviderError, MixingMultiProvidersWithRegularProvidersError, NoAnnotationError} from './reflective_errors';
|
||||
import {invalidProviderError, mixingMultiProvidersWithRegularProvidersError, noAnnotationError} from './reflective_errors';
|
||||
import {ReflectiveKey} from './reflective_key';
|
||||
|
||||
|
||||
@ -154,7 +154,7 @@ export function mergeResolvedReflectiveProviders(
|
||||
const existing = normalizedProvidersMap.get(provider.key.id);
|
||||
if (existing) {
|
||||
if (provider.multiProvider !== existing.multiProvider) {
|
||||
throw new MixingMultiProvidersWithRegularProvidersError(existing, provider);
|
||||
throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
|
||||
}
|
||||
if (provider.multiProvider) {
|
||||
for (let j = 0; j < provider.resolvedFactories.length; j++) {
|
||||
@ -189,7 +189,7 @@ function _normalizeProviders(providers: Provider[], res: Provider[]): Provider[]
|
||||
_normalizeProviders(b, res);
|
||||
|
||||
} else {
|
||||
throw new InvalidProviderError(b);
|
||||
throw invalidProviderError(b);
|
||||
}
|
||||
});
|
||||
|
||||
@ -211,7 +211,7 @@ function _dependenciesFor(typeOrFunc: any): ReflectiveDependency[] {
|
||||
|
||||
if (!params) return [];
|
||||
if (params.some(p => p == null)) {
|
||||
throw new NoAnnotationError(typeOrFunc, params);
|
||||
throw noAnnotationError(typeOrFunc, params);
|
||||
}
|
||||
return params.map(p => _extractToken(typeOrFunc, p, params));
|
||||
}
|
||||
@ -253,7 +253,7 @@ function _extractToken(
|
||||
if (token != null) {
|
||||
return _createDependency(token, optional, visibility);
|
||||
} else {
|
||||
throw new NoAnnotationError(typeOrFunc, params);
|
||||
throw noAnnotationError(typeOrFunc, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {WrappedError} from './facade/errors';
|
||||
import {ERROR_ORIGINAL_ERROR, getDebugContext, getOriginalError} from './errors';
|
||||
|
||||
|
||||
/**
|
||||
* @whatItDoes Provides a hook for centralized exception handling.
|
||||
@ -48,24 +49,26 @@ export class ErrorHandler {
|
||||
constructor(rethrowError: boolean = true) { this.rethrowError = rethrowError; }
|
||||
|
||||
handleError(error: any): void {
|
||||
const originalError = this._findOriginalError(error);
|
||||
const originalStack = this._findOriginalStack(error);
|
||||
const context = this._findContext(error);
|
||||
|
||||
this._console.error(`EXCEPTION: ${this._extractMessage(error)}`);
|
||||
|
||||
if (originalError) {
|
||||
this._console.error(`ORIGINAL EXCEPTION: ${this._extractMessage(originalError)}`);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
const originalError = this._findOriginalError(error);
|
||||
const originalStack = this._findOriginalStack(error);
|
||||
const context = this._findContext(error);
|
||||
|
||||
if (originalStack) {
|
||||
this._console.error('ORIGINAL STACKTRACE:');
|
||||
this._console.error(originalStack);
|
||||
}
|
||||
if (originalError) {
|
||||
this._console.error(`ORIGINAL EXCEPTION: ${this._extractMessage(originalError)}`);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
this._console.error('ERROR CONTEXT:');
|
||||
this._console.error(context);
|
||||
if (originalStack) {
|
||||
this._console.error('ORIGINAL STACKTRACE:');
|
||||
this._console.error(originalStack);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
this._console.error('ERROR CONTEXT:');
|
||||
this._console.error(context);
|
||||
}
|
||||
}
|
||||
|
||||
// We rethrow exceptions, so operations like 'bootstrap' will result in an error
|
||||
@ -81,31 +84,29 @@ export class ErrorHandler {
|
||||
/** @internal */
|
||||
_findContext(error: any): any {
|
||||
if (error) {
|
||||
return error.context ? error.context :
|
||||
this._findContext((error as WrappedError).originalError);
|
||||
return getDebugContext(error) ? getDebugContext(error) :
|
||||
this._findContext(getOriginalError(error));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_findOriginalError(error: any): any {
|
||||
let e = (error as WrappedError).originalError;
|
||||
while (e && (e as WrappedError).originalError) {
|
||||
e = (e as WrappedError).originalError;
|
||||
_findOriginalError(error: Error): any {
|
||||
let e = getOriginalError(error);
|
||||
while (e && getOriginalError(e)) {
|
||||
e = getOriginalError(e);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_findOriginalStack(error: any): string {
|
||||
if (!(error instanceof Error)) return null;
|
||||
|
||||
_findOriginalStack(error: Error): string {
|
||||
let e: any = error;
|
||||
let stack: string = e.stack;
|
||||
while (e instanceof Error && (e as WrappedError).originalError) {
|
||||
e = (e as WrappedError).originalError;
|
||||
while (e instanceof Error && getOriginalError(e)) {
|
||||
e = getOriginalError(e);
|
||||
if (e instanceof Error && e.stack) {
|
||||
stack = e.stack;
|
||||
}
|
||||
@ -114,3 +115,11 @@ export class ErrorHandler {
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
||||
export function wrappedError(message: string, originalError: any): Error {
|
||||
const msg =
|
||||
`${message} caused by: ${originalError instanceof Error ? originalError.message: originalError }`;
|
||||
const error = Error(msg);
|
||||
(error as any)[ERROR_ORIGINAL_ERROR] = originalError;
|
||||
return error;
|
||||
}
|
||||
|
28
modules/@angular/core/src/errors.ts
Normal file
28
modules/@angular/core/src/errors.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @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 {Type} from './type';
|
||||
import {DebugContext} from './view';
|
||||
|
||||
export const ERROR_TYPE = 'ngType';
|
||||
export const ERROR_COMPONENT_TYPE = 'ngComponentType';
|
||||
export const ERROR_DEBUG_CONTEXT = 'ngDebugContext';
|
||||
export const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
|
||||
|
||||
|
||||
export function getType(error: Error): Function {
|
||||
return (error as any)[ERROR_TYPE];
|
||||
}
|
||||
|
||||
export function getDebugContext(error: Error): DebugContext {
|
||||
return (error as any)[ERROR_DEBUG_CONTEXT];
|
||||
}
|
||||
|
||||
export function getOriginalError(error: Error): Error {
|
||||
return (error as any)[ERROR_ORIGINAL_ERROR];
|
||||
}
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import {Injectable, InjectionToken} from '../di';
|
||||
import {BaseError} from '../facade/errors';
|
||||
import {stringify} from '../facade/lang';
|
||||
import {MissingTranslationStrategy} from '../i18n/tokens';
|
||||
import {ViewEncapsulation} from '../metadata';
|
||||
@ -16,19 +15,6 @@ import {Type} from '../type';
|
||||
import {ComponentFactory} from './component_factory';
|
||||
import {NgModuleFactory} from './ng_module_factory';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Indicates that a component is still being loaded in a synchronous compile.
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
export class ComponentStillLoadingError extends BaseError {
|
||||
constructor(public compType: Type<any>) {
|
||||
super(`Can't compile synchronously as ${stringify(compType)} is still being loaded!`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combination of NgModuleFactory and ComponentFactorys.
|
||||
*
|
||||
@ -59,8 +45,7 @@ function _throwError() {
|
||||
export class Compiler {
|
||||
/**
|
||||
* Compiles the given NgModule and all of its components. All templates of the components listed
|
||||
* in `entryComponents`
|
||||
* have to be inlined. Otherwise throws a {@link ComponentStillLoadingError}.
|
||||
* in `entryComponents` have to be inlined.
|
||||
*/
|
||||
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> { throw _throwError(); }
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {BaseError} from '../facade/errors';
|
||||
import {stringify} from '../facade/lang';
|
||||
import {Type} from '../type';
|
||||
|
||||
@ -14,19 +13,23 @@ import {ComponentFactory} from './component_factory';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @stable
|
||||
*/
|
||||
export class NoComponentFactoryError extends BaseError {
|
||||
constructor(public component: Function) {
|
||||
super(
|
||||
`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
|
||||
}
|
||||
export function noComponentFactoryError(component: Function) {
|
||||
const error = Error(
|
||||
`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
|
||||
(error as any)[ERROR_COMPONENT] = component;
|
||||
return error;
|
||||
}
|
||||
|
||||
const ERROR_COMPONENT = 'ngComponent';
|
||||
|
||||
export function getComponent(error: Error): Type<any> {
|
||||
return (error as any)[ERROR_COMPONENT];
|
||||
}
|
||||
|
||||
|
||||
class _NullComponentFactoryResolver implements ComponentFactoryResolver {
|
||||
resolveComponentFactory<T>(component: {new (...args: any[]): T}): ComponentFactory<T> {
|
||||
throw new NoComponentFactoryError(component);
|
||||
throw noComponentFactoryError(component);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {BaseError, WrappedError} from '../facade/errors';
|
||||
|
||||
import {wrappedError} from '../error_handler';
|
||||
import {ERROR_DEBUG_CONTEXT, ERROR_TYPE} from '../errors';
|
||||
import {DebugContext} from './debug_context';
|
||||
|
||||
|
||||
@ -41,19 +41,19 @@ import {DebugContext} from './debug_context';
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @stable
|
||||
*/
|
||||
export class ExpressionChangedAfterItHasBeenCheckedError extends BaseError {
|
||||
constructor(oldValue: any, currValue: any, isFirstCheck: boolean) {
|
||||
let msg =
|
||||
`Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`;
|
||||
if (isFirstCheck) {
|
||||
msg +=
|
||||
` It seems like the view has been created after its parent and its children have been dirty checked.` +
|
||||
` Has it been created in a change detection hook ?`;
|
||||
}
|
||||
super(msg);
|
||||
export function expressionChangedAfterItHasBeenCheckedError(
|
||||
oldValue: any, currValue: any, isFirstCheck: boolean) {
|
||||
let msg =
|
||||
`Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`;
|
||||
if (isFirstCheck) {
|
||||
msg +=
|
||||
` It seems like the view has been created after its parent and its children have been dirty checked.` +
|
||||
` Has it been created in a change detection hook ?`;
|
||||
}
|
||||
const error = Error(msg);
|
||||
(error as any)[ERROR_TYPE] = expressionChangedAfterItHasBeenCheckedError;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,28 +61,21 @@ export class ExpressionChangedAfterItHasBeenCheckedError extends BaseError {
|
||||
*
|
||||
* This error wraps the original exception to attach additional contextual information that can
|
||||
* be useful for debugging.
|
||||
* @stable
|
||||
*/
|
||||
export class ViewWrappedError extends WrappedError {
|
||||
/**
|
||||
* DebugContext
|
||||
*/
|
||||
context: DebugContext;
|
||||
|
||||
constructor(originalError: any, context: DebugContext) {
|
||||
super(`Error in ${context.source}`, originalError);
|
||||
this.context = context;
|
||||
}
|
||||
export function viewWrappedError(originalError: any, context: DebugContext): Error {
|
||||
const error = wrappedError(`Error in ${context.source}`, originalError);
|
||||
(error as any)[ERROR_DEBUG_CONTEXT] = context;
|
||||
(error as any)[ERROR_TYPE] = viewWrappedError;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a destroyed view is used.
|
||||
*
|
||||
* This error indicates a bug in the framework.
|
||||
*
|
||||
* This is an internal Angular error.
|
||||
* @stable
|
||||
*/
|
||||
export class ViewDestroyedError extends BaseError {
|
||||
constructor(details: string) { super(`Attempt to use a destroyed view: ${details}`); }
|
||||
* Thrown when a destroyed view is used.
|
||||
*
|
||||
* This error indicates a bug in the framework.
|
||||
*
|
||||
* This is an internal Angular error.
|
||||
*/
|
||||
export function viewDestroyedError(details: string) {
|
||||
return Error(`Attempt to use a destroyed view: ${details}`);
|
||||
}
|
||||
|
@ -6,9 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
import {ApplicationRef} from '../application_ref';
|
||||
import {ChangeDetectorRef, ChangeDetectorStatus} from '../change_detection/change_detection';
|
||||
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
||||
import {getType} from '../errors';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
||||
import {DirectRenderer, RenderComponentType, Renderer} from '../render/api';
|
||||
@ -17,7 +19,7 @@ import {AnimationViewContext} from './animation_view_context';
|
||||
import {ComponentRef} from './component_factory';
|
||||
import {DebugContext, StaticNodeDebugInfo} from './debug_context';
|
||||
import {ElementInjector} from './element_injector';
|
||||
import {ExpressionChangedAfterItHasBeenCheckedError, ViewDestroyedError, ViewWrappedError} from './errors';
|
||||
import {expressionChangedAfterItHasBeenCheckedError, viewDestroyedError, viewWrappedError} from './errors';
|
||||
import {ViewContainer} from './view_container';
|
||||
import {ViewRef_} from './view_ref';
|
||||
import {ViewType} from './view_type';
|
||||
@ -360,7 +362,7 @@ export abstract class AppView<T> {
|
||||
return cb;
|
||||
}
|
||||
|
||||
throwDestroyedError(details: string): void { throw new ViewDestroyedError(details); }
|
||||
throwDestroyedError(details: string): void { throw viewDestroyedError(details); }
|
||||
}
|
||||
|
||||
export class DebugAppView<T> extends AppView<T> {
|
||||
@ -445,12 +447,12 @@ export class DebugAppView<T> extends AppView<T> {
|
||||
}
|
||||
|
||||
private _rethrowWithContext(e: any) {
|
||||
if (!(e instanceof ViewWrappedError)) {
|
||||
if (!(e instanceof ExpressionChangedAfterItHasBeenCheckedError)) {
|
||||
if (!(getType(e) == viewWrappedError)) {
|
||||
if (!(getType(e) == expressionChangedAfterItHasBeenCheckedError)) {
|
||||
this.cdMode = ChangeDetectorStatus.Errored;
|
||||
}
|
||||
if (isPresent(this._currentDebugContext)) {
|
||||
throw new ViewWrappedError(e, this._currentDebugContext);
|
||||
throw viewWrappedError(e, this._currentDebugContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import {Type} from '../type';
|
||||
import {VERSION} from '../version';
|
||||
|
||||
import {ComponentFactory} from './component_factory';
|
||||
import {ExpressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||
import {AppView} from './view';
|
||||
|
||||
@Injectable()
|
||||
@ -104,7 +104,7 @@ export function checkBinding(
|
||||
const isFirstCheck = view.numberOfChecks === 0;
|
||||
if (view.throwOnChange) {
|
||||
if (isFirstCheck || !devModeEqual(oldValue, newValue)) {
|
||||
throw new ExpressionChangedAfterItHasBeenCheckedError(oldValue, newValue, isFirstCheck);
|
||||
throw expressionChangedAfterItHasBeenCheckedError(oldValue, newValue, isFirstCheck);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
|
@ -6,12 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {BaseError, WrappedError} from '../facade/errors';
|
||||
|
||||
import {ERROR_DEBUG_CONTEXT, ERROR_ORIGINAL_ERROR, getDebugContext} from '../errors';
|
||||
import {DebugContext, EntryAction, ViewState} from './types';
|
||||
|
||||
export function expressionChangedAfterItHasBeenCheckedError(
|
||||
context: DebugContext, oldValue: any, currValue: any, isFirstCheck: boolean): ViewDebugError {
|
||||
context: DebugContext, oldValue: any, currValue: any, isFirstCheck: boolean): Error {
|
||||
let msg =
|
||||
`Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`;
|
||||
if (isFirstCheck) {
|
||||
@ -22,25 +21,22 @@ export function expressionChangedAfterItHasBeenCheckedError(
|
||||
return viewDebugError(msg, context);
|
||||
}
|
||||
|
||||
export function viewWrappedDebugError(originalError: any, context: DebugContext): WrappedError&
|
||||
ViewDebugError {
|
||||
const err = viewDebugError(originalError.message, context) as WrappedError & ViewDebugError;
|
||||
err.originalError = originalError;
|
||||
export function viewWrappedDebugError(originalError: any, context: DebugContext): Error {
|
||||
const err = viewDebugError(originalError.message, context);
|
||||
(err as any)[ERROR_ORIGINAL_ERROR] = originalError;
|
||||
return err;
|
||||
}
|
||||
|
||||
export interface ViewDebugError { context: DebugContext; }
|
||||
|
||||
export function viewDebugError(msg: string, context: DebugContext): ViewDebugError {
|
||||
const err = new Error(msg) as any;
|
||||
err.context = context;
|
||||
export function viewDebugError(msg: string, context: DebugContext): Error {
|
||||
const err = new Error(msg);
|
||||
(err as any)[ERROR_DEBUG_CONTEXT] = context;
|
||||
err.stack = context.source;
|
||||
context.view.state |= ViewState.Errored;
|
||||
return err;
|
||||
}
|
||||
|
||||
export function isViewDebugError(err: any): boolean {
|
||||
return err.context;
|
||||
export function isViewDebugError(err: Error): boolean {
|
||||
return !!getDebugContext(err);
|
||||
}
|
||||
|
||||
export function viewDestroyedError(action: EntryAction): Error {
|
||||
|
@ -6,9 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {isDevMode} from '../application_ref';
|
||||
import {RenderComponentType, Renderer} from '../render/api';
|
||||
|
||||
import {checkAndUpdateElementDynamic, checkAndUpdateElementInline, createElement} from './element';
|
||||
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||
import {appendNgContent} from './ng_content';
|
||||
|
Reference in New Issue
Block a user