The main use case for the generated source maps is to give
errors a meaningful context in terms of the original source
that the user wrote.
Related changes that are included in this commit:
* renamed virtual folders used for jit:
* ng://<module type>/module.ngfactory.js
* ng://<module type>/<comp type>.ngfactory.js
* ng://<module type>/<comp type>.html (for inline templates)
* error logging:
* all errors that happen in templates are logged
from the place of the nearest element.
* instead of logging error messages and stacks separately,
we log the actual error. This is needed so that browsers apply
source maps to the stack correctly.
* error type and error is logged as one log entry.
Note that long-stack-trace zone has a bug that
disables source maps for stack traces,
see https://github.com/angular/zone.js/issues/661.
BREAKING CHANGE:
- DebugNode.source no more returns the source location of a node.
Closes 14013
52 lines
1.8 KiB
TypeScript
52 lines
1.8 KiB
TypeScript
/**
|
|
* @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 {ERROR_DEBUG_CONTEXT, ERROR_LOGGER, getDebugContext} from '../errors';
|
|
import {DebugContext, ViewState} from './types';
|
|
|
|
export function expressionChangedAfterItHasBeenCheckedError(
|
|
context: DebugContext, oldValue: any, currValue: any, isFirstCheck: boolean): Error {
|
|
let msg =
|
|
`ExpressionChangedAfterItHasBeenCheckedError: 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 ?`;
|
|
}
|
|
return viewDebugError(msg, context);
|
|
}
|
|
|
|
export function viewWrappedDebugError(err: any, context: DebugContext): Error {
|
|
if (!(err instanceof Error)) {
|
|
// errors that are not Error instances don't have a stack,
|
|
// so it is ok to wrap them into a new Error object...
|
|
err = new Error(err.toString());
|
|
}
|
|
_addDebugContext(err, context);
|
|
return err;
|
|
}
|
|
|
|
export function viewDebugError(msg: string, context: DebugContext): Error {
|
|
const err = new Error(msg);
|
|
_addDebugContext(err, context);
|
|
return err;
|
|
}
|
|
|
|
function _addDebugContext(err: Error, context: DebugContext) {
|
|
(err as any)[ERROR_DEBUG_CONTEXT] = context;
|
|
(err as any)[ERROR_LOGGER] = context.logError.bind(context);
|
|
}
|
|
|
|
export function isViewDebugError(err: Error): boolean {
|
|
return !!getDebugContext(err);
|
|
}
|
|
|
|
export function viewDestroyedError(action: string): Error {
|
|
return new Error(`ViewDestroyedError: Attempt to use a destroyed view: ${action}`);
|
|
}
|