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);  /**  | 
