aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMisko Hevery2010-11-16 13:57:41 -0800
committerIgor Minar2010-11-16 14:19:55 -0800
commitb2d63ac48bdc61b5a4afdd10b8485c0c1ab8cdca (patch)
tree0b798ba07d5b593dcc3e27964e81eb0542440d56 /src
parent4af32de84a264e05eebfa6dbc09ce10fac1e1417 (diff)
downloadangular.js-b2d63ac48bdc61b5a4afdd10b8485c0c1ab8cdca.tar.bz2
Changed error handling so that better stack traces are displayed in the ng-errors
Diffstat (limited to 'src')
-rw-r--r--src/Angular.js13
-rw-r--r--src/Scope.js2
-rw-r--r--src/directives.js10
-rw-r--r--src/parser.js83
-rw-r--r--src/services.js27
5 files changed, 71 insertions, 64 deletions
diff --git a/src/Angular.js b/src/Angular.js
index 5a5a4ab3..e0cf2df4 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -84,6 +84,7 @@ var _undefined = undefined,
PRIORITY_WATCH = -1000,
PRIORITY_LAST = 99999,
PRIORITY = {'FIRST': PRIORITY_FIRST, 'LAST': PRIORITY_LAST, 'WATCH':PRIORITY_WATCH},
+ Error = window.Error,
jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy
_ = window['_'],
/** holds major version number for IE or NaN for real browsers */
@@ -557,6 +558,18 @@ function foreachSorted(obj, iterator, context) {
}
+function formatError(arg) {
+ if (arg instanceof Error) {
+ if (arg.stack) {
+ arg = arg.stack;
+ } else if (arg.sourceURL) {
+ arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
+ }
+ }
+ return arg;
+}
+
+
function extend(dst) {
foreach(arguments, function(obj){
if (obj !== dst) {
diff --git a/src/Scope.js b/src/Scope.js
index 1f8e81e5..64019be4 100644
--- a/src/Scope.js
+++ b/src/Scope.js
@@ -101,7 +101,7 @@ function expressionCompile(exp){
}
function errorHandlerFor(element, error) {
- elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error);
+ elementError(element, NG_EXCEPTION, isDefined(error) ? formatError(error) : error);
}
function createScope(parent, providers, instanceCache) {
diff --git a/src/directives.js b/src/directives.js
index e359d6cc..2958773d 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -182,7 +182,7 @@ angularDirective("ng:bind", function(expression, element){
oldElement = this.hasOwnProperty($$element) ? this.$element : _undefined;
this.$element = element;
value = this.$tryEval(expression, function(e){
- error = toJson(e);
+ error = formatError(e);
});
this.$element = oldElement;
// If we are HTML than save the raw HTML data so that we don't
@@ -466,15 +466,15 @@ angularWidget("@ng:repeat", function(expression, element){
var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
lhs, rhs, valueIdent, keyIdent;
if (! match) {
- throw "Expected ng:repeat in form of 'item in collection' but got '" +
- expression + "'.";
+ throw Error("Expected ng:repeat in form of 'item in collection' but got '" +
+ expression + "'.");
}
lhs = match[1];
rhs = match[2];
match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
if (!match) {
- throw "'item' in 'item in collection' should be identifier or (key, value) but got '" +
- keyValue + "'.";
+ throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
+ keyValue + "'.");
}
valueIdent = match[3] || match[1];
keyIdent = match[2];
diff --git a/src/parser.js b/src/parser.js
index 85b9c651..992696ee 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -67,10 +67,7 @@ function lex(text, parseStringsForObjects){
tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')});
index += 1;
} else {
- throw "Lexer Error: Unexpected next character [" +
- text.substring(index) +
- "] in expression '" + text +
- "' at column '" + (index+1) + "'.";
+ throwError("Unexpected next character ", index, index+1);
}
}
lastCh = ch;
@@ -103,6 +100,16 @@ function lex(text, parseStringsForObjects){
function isExpOperator(ch) {
return ch == '-' || ch == '+' || isNumber(ch);
}
+
+ function throwError(error, start, end) {
+ end = end || index;
+ throw Error("Lexer Error: " + error + " at column" +
+ (isDefined(start) ?
+ "s " + start + "-" + index + " [" + text.substring(start, end) + "]" :
+ " " + end) +
+ " in expression [" + text + "].");
+ }
+
function readNumber() {
var number = "";
var start = index;
@@ -121,7 +128,7 @@ function lex(text, parseStringsForObjects){
} else if (isExpOperator(ch) &&
(!peekCh || !isNumber(peekCh)) &&
number.charAt(number.length - 1) == 'e') {
- throw 'Lexer found invalid exponential value "' + text + '"';
+ throwError('Invalid exponent');
} else {
break;
}
@@ -151,7 +158,7 @@ function lex(text, parseStringsForObjects){
}
tokens.push({index:start, text:ident, fn:fn, json: OPERATORS[ident]});
}
-
+
function readString(quote) {
var start = index;
index++;
@@ -165,9 +172,7 @@ function lex(text, parseStringsForObjects){
if (ch == 'u') {
var hex = text.substring(index + 1, index + 5);
if (!hex.match(/[\da-f]{4}/i))
- throw "Lexer Error: Invalid unicode escape [\\u" +
- hex + "] starting at column '" +
- start + "' in expression '" + text + "'.";
+ throwError( "Invalid unicode escape [\\u" + hex + "]");
index += 4;
string += String.fromCharCode(parseInt(hex, 16));
} else {
@@ -194,9 +199,7 @@ function lex(text, parseStringsForObjects){
}
index++;
}
- throw "Lexer Error: Unterminated quote [" +
- text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + text + "'.";
+ throwError("Unterminated quote", start);
}
function readRegexp(quote) {
var start = index;
@@ -227,9 +230,7 @@ function lex(text, parseStringsForObjects){
}
index++;
}
- throw "Lexer Error: Unterminated RegExp [" +
- text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + text + "'.";
+ throwError("Unterminated RegExp", start);
}
}
@@ -249,17 +250,16 @@ function parser(text, json){
};
///////////////////////////////////
-
- function error(msg, token) {
- throw "Token '" + token.text +
- "' is " + msg + " at column='" +
- (token.index + 1) + "' of expression '" +
- text + "' starting at '" + text.substring(token.index) + "'.";
+ function throwError(msg, token) {
+ throw Error("Parse Error: Token '" + token.text +
+ "' " + msg + " at column " +
+ (token.index + 1) + " of expression [" +
+ text + "] starting at [" + text.substring(token.index) + "].");
}
function peekToken() {
if (tokens.length === 0)
- throw "Unexpected end of expression: " + text;
+ throw Error("Unexpected end of expression: " + text);
return tokens[0];
}
@@ -280,10 +280,7 @@ function parser(text, json){
if (token) {
if (json && !token.json) {
index = token.index;
- throw "Expression at column='" +
- token.index + "' of expression '" +
- text + "' starting at '" + text.substring(token.index) +
- "' is not valid json.";
+ throwError("is not valid json", token);
}
tokens.shift();
this.currentToken = token;
@@ -294,11 +291,7 @@ function parser(text, json){
function consume(e1){
if (!expect(e1)) {
- var token = peek();
- throw "Expecting '" + e1 + "' at column '" +
- (token.index+1) + "' in '" +
- text + "' got '" +
- text.substring(token.index) + "'.";
+ throwError("is unexpected, expecting [" + e1 + "]", peek());
}
}
@@ -320,8 +313,7 @@ function parser(text, json){
function assertAllConsumed(){
if (tokens.length !== 0) {
- throw "Did not understand '" + text.substring(tokens[0].index) +
- "' while evaluating '" + text + "'.";
+ throwError("is extra token not part of expression", tokens[0]);
}
}
@@ -387,18 +379,7 @@ function parser(text, json){
}
function expression(){
- return throwStmt();
- }
-
- function throwStmt(){
- if (expect('throw')) {
- var throwExp = assignment();
- return function (self) {
- throw throwExp(self);
- };
- } else {
- return assignment();
- }
+ return assignment();
}
function assignment(){
@@ -406,9 +387,8 @@ function parser(text, json){
var token;
if (token = expect('=')) {
if (!left.isAssignable) {
- throw "Left hand side '" +
- text.substring(0, token.index) + "' of assignment '" +
- text.substring(token.index) + "' is not assignable.";
+ throwError("implies assignment but [" +
+ text.substring(0, token.index) + "] can not be assigned to", token);
}
var ident = function(){return left.isAssignable;};
return binaryFn(ident, token.fn, logicalOR());
@@ -498,8 +478,7 @@ function parser(text, json){
instance = instance[key];
}
if (typeof instance != $function) {
- throw "Function '" + token.text + "' at column '" +
- (token.index+1) + "' in '" + text + "' is not defined.";
+ throwError("should be a function", token);
}
return instance;
}
@@ -518,7 +497,7 @@ function parser(text, json){
var token = expect();
primary = token.fn;
if (!primary) {
- error("not a primary expression", token);
+ throwError("not a primary expression", token);
}
}
var next;
@@ -530,7 +509,7 @@ function parser(text, json){
} else if (next.text === '.') {
primary = fieldAccess(primary);
} else {
- throw "IMPOSSIBLE";
+ throwError("IMPOSSIBLE");
}
}
return primary;
diff --git a/src/services.js b/src/services.js
index be442c20..5dfc64f7 100644
--- a/src/services.js
+++ b/src/services.js
@@ -311,8 +311,6 @@ angularServiceInject("$location", function(browser) {
<button ng:click="$log.error(message)">error</button>
*/
angularServiceInject("$log", function($window){
- var console = $window.console || {log: noop, warn: noop, info: noop, error: noop},
- log = console.log || noop;
return {
/**
* @ngdoc method
@@ -322,7 +320,7 @@ angularServiceInject("$log", function($window){
* @description
* Write a log message
*/
- log: bind(console, log),
+ log: consoleLog('log'),
/**
* @ngdoc method
@@ -332,7 +330,7 @@ angularServiceInject("$log", function($window){
* @description
* Write a warning message
*/
- warn: bind(console, console.warn || log),
+ warn: consoleLog('warn'),
/**
* @ngdoc method
@@ -342,7 +340,7 @@ angularServiceInject("$log", function($window){
* @description
* Write an information message
*/
- info: bind(console, console.info || log),
+ info: consoleLog('info'),
/**
* @ngdoc method
@@ -352,8 +350,25 @@ angularServiceInject("$log", function($window){
* @description
* Write an error message
*/
- error: bind(console, console.error || log)
+ error: consoleLog('error')
};
+
+ function consoleLog(type) {
+ var console = $window.console || {};
+ var logFn = console[type] || console.log || noop;
+ if (logFn.apply) {
+ return function(){
+ var args = [];
+ foreach(arguments, function(arg){
+ args.push(formatError(arg));
+ });
+ return logFn.apply(console, args);
+ };
+ } else {
+ // we are IE, in which case there is nothing we can do
+ return logFn;
+ }
+ }
}, ['$window'], EAGER_PUBLISHED);
/**