diff options
| author | Misko Hevery | 2010-11-16 13:57:41 -0800 |
|---|---|---|
| committer | Igor Minar | 2010-11-16 14:19:55 -0800 |
| commit | b2d63ac48bdc61b5a4afdd10b8485c0c1ab8cdca (patch) | |
| tree | 0b798ba07d5b593dcc3e27964e81eb0542440d56 /src | |
| parent | 4af32de84a264e05eebfa6dbc09ce10fac1e1417 (diff) | |
| download | angular.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.js | 13 | ||||
| -rw-r--r-- | src/Scope.js | 2 | ||||
| -rw-r--r-- | src/directives.js | 10 | ||||
| -rw-r--r-- | src/parser.js | 83 | ||||
| -rw-r--r-- | src/services.js | 27 |
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); /** |
