diff options
| author | Igor Minar | 2013-05-24 11:00:14 -0700 | 
|---|---|---|
| committer | Vojta Jina | 2013-05-24 17:03:21 -0700 | 
| commit | b8ea7f6aba2e675b85826b0bee1f21ddd7b866a5 (patch) | |
| tree | f3b34e25e27d088bec9b698b246d49f86281de36 /src/ng | |
| parent | 88eaea8e7bf025a7805a5d20f5d47472e4f26f6f (diff) | |
| download | angular.js-b8ea7f6aba2e675b85826b0bee1f21ddd7b866a5.tar.bz2 | |
feat(ngError): add error message compression and better error messages
- add toThrowNg matcher
Diffstat (limited to 'src/ng')
| -rw-r--r-- | src/ng/cacheFactory.js | 2 | ||||
| -rw-r--r-- | src/ng/compile.js | 33 | ||||
| -rw-r--r-- | src/ng/controller.js | 5 | ||||
| -rw-r--r-- | src/ng/directive/input.js | 7 | ||||
| -rw-r--r-- | src/ng/directive/ngRepeat.js | 12 | ||||
| -rw-r--r-- | src/ng/directive/select.js | 8 | ||||
| -rw-r--r-- | src/ng/httpBackend.js | 2 | ||||
| -rw-r--r-- | src/ng/interpolate.js | 2 | ||||
| -rw-r--r-- | src/ng/location.js | 6 | ||||
| -rw-r--r-- | src/ng/parse.js | 23 | ||||
| -rw-r--r-- | src/ng/rootScope.js | 11 | 
11 files changed, 50 insertions, 61 deletions
| diff --git a/src/ng/cacheFactory.js b/src/ng/cacheFactory.js index ce690ebf..1c23e063 100644 --- a/src/ng/cacheFactory.js +++ b/src/ng/cacheFactory.js @@ -28,7 +28,7 @@ function $CacheFactoryProvider() {      function cacheFactory(cacheId, options) {        if (cacheId in caches) { -        throw Error('cacheId ' + cacheId + ' taken'); +        throw ngError(10, "CacheId '{0}' is already taken!", cacheId);        }        var size = 0, diff --git a/src/ng/compile.js b/src/ng/compile.js index 96529d3c..be22482b 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -18,9 +18,6 @@   */ -var NON_ASSIGNABLE_MODEL_EXPRESSION = 'Non-assignable model expression: '; - -  /**   * @ngdoc function   * @name ng.$compile @@ -155,7 +152,6 @@ function $CompileProvider($provide) {        Suffix = 'Directive',        COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,        CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/, -      MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',        urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/; @@ -392,10 +388,6 @@ function $CompileProvider($provide) {        };      } -    function wrongMode(localName, mode) { -      throw Error("Unsupported '" + mode + "' for '" + localName + "'."); -    } -      function safeAddClass($element, className) {        try {          $element.addClass(className); @@ -669,7 +661,7 @@ function $CompileProvider($provide) {              compileNode = $template[0];              if ($template.length != 1 || compileNode.nodeType !== 1) { -              throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue); +              throw ngError(12, "Template for directive '{0}' must have exactly one root element.", directiveName);              }              replaceWith(jqCollection, $compileNode, compileNode); @@ -755,7 +747,7 @@ function $CompileProvider($provide) {            }            value = $element[retrievalMethod]('$' + require + 'Controller');            if (!value && !optional) { -            throw Error("No controller: " + require); +            throw ngError(13, "Controller '{0}', required by directive '{1}', can't be found!", require, directiveName);            }            return value;          } else if (isArray(require)) { @@ -783,8 +775,8 @@ function $CompileProvider($provide) {            var parentScope = scope.$parent || scope; -          forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) { -            var match = definiton.match(LOCAL_REGEXP) || [], +          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) { +            var match = definition.match(LOCAL_REGEXP) || [],                  attrName = match[3] || scopeName,                  optional = (match[2] == '?'),                  mode = match[1], // @, =, or & @@ -815,8 +807,8 @@ function $CompileProvider($provide) {                  parentSet = parentGet.assign || function() {                    // reset the change, or we will throw this exception on every $digest                    lastValue = scope[scopeName] = parentGet(parentScope); -                  throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] + -                      ' (directive: ' + newIsolateScopeDirective.name + ')'); +                  throw ngError(14, "Expression '{0}' used with directive '{1}' is non-assignable!", +                      attrs[attrName], newIsolateScopeDirective.name);                  };                  lastValue = scope[scopeName] = parentGet(parentScope);                  scope.$watch(function parentValueWatch() { @@ -846,8 +838,8 @@ function $CompileProvider($provide) {                }                default: { -                throw Error('Invalid isolate scope definition for directive ' + -                    newIsolateScopeDirective.name + ': ' + definiton); +                throw ngError(15, "Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}", +                    newIsolateScopeDirective.name, scopeName, definition);                }              }            }); @@ -1000,7 +992,8 @@ function $CompileProvider($provide) {              compileNode = $template[0];              if ($template.length != 1 || compileNode.nodeType !== 1) { -              throw new Error(MULTI_ROOT_TEMPLATE_ERROR + content); +              throw ngError(16, "Template for directive '{0}' must have exactly one root element. Template: {1}", +                  origAsyncDirective.name, templateUrl);              }              tempTemplateAttrs = {$attr: {}}; @@ -1037,7 +1030,7 @@ function $CompileProvider($provide) {            linkQueue = null;          }).          error(function(response, code, headers, config) { -          throw Error('Failed to load template: ' + config.url); +          throw ngError(17, 'Failed to load template: {0}', config.url);          });        return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) { @@ -1065,8 +1058,8 @@ function $CompileProvider($provide) {      function assertNoDuplicate(what, previousDirective, directive, element) {        if (previousDirective) { -        throw Error('Multiple directives [' + previousDirective.name + ', ' + -          directive.name + '] asking for ' + what + ' on: ' +  startingTag(element)); +        throw ngError(18, 'Multiple directives [{0}, {1}] asking for {2} on: {3}', +            previousDirective.name, directive.name, what, startingTag(element));        }      } diff --git a/src/ng/controller.js b/src/ng/controller.js index 5c19cf88..2df0bde9 100644 --- a/src/ng/controller.js +++ b/src/ng/controller.js @@ -74,9 +74,8 @@ function $ControllerProvider() {        instance = $injector.instantiate(expression, locals);        if (identifier) { -        if (typeof locals.$scope !== 'object') { -          throw new Error('Can not export controller as "' + identifier + '". ' + -              'No scope object provided!'); +        if (!(locals && typeof locals.$scope == 'object')) { +          throw ngError(47, "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", constructor || expression.name, identifier);          }          locals.$scope[identifier] = instance; diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 543ed367..610396a5 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -475,7 +475,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {          var patternObj = scope.$eval(pattern);          if (!patternObj || !patternObj.test) { -          throw new Error('Expected ' + pattern + ' to be a RegExp but was ' + patternObj); +          throw ngError(5, 'ngPattern error! Expected {0} to be a RegExp but was {1}. Element: {2}', +                                                      pattern,                   patternObj,   startingTag(element));          }          return validate(patternObj, value);        }; @@ -918,8 +919,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$        ngModelSet = ngModelGet.assign;    if (!ngModelSet) { -    throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + $attr.ngModel + -        ' (' + startingTag($element) + ')'); +    throw ngError(6, "ngModel error! Expression '{0}' is non-assignable. Element: {1}", $attr.ngModel, +        startingTag($element));    }    /** diff --git a/src/ng/directive/ngRepeat.js b/src/ng/directive/ngRepeat.js index 330f6abb..34d32f59 100644 --- a/src/ng/directive/ngRepeat.js +++ b/src/ng/directive/ngRepeat.js @@ -157,8 +157,8 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {            hashFnLocals = {$id: hashKey};          if (!match) { -          throw Error("Expected ngRepeat in form of '_item_ in _collection_[ track by _id_]' but got '" + -            expression + "'."); +          throw ngError(7, "ngRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", +            expression);          }          lhs = match[1]; @@ -182,8 +182,8 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {          match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);          if (!match) { -          throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" + -              lhs + "'."); +          throw ngError(8, "ngRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.", +                                                                    lhs);          }          valueIdentifier = match[3] || match[1];          keyIdentifier = match[2]; @@ -244,8 +244,8 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {                 if (block && block.element) lastBlockMap[block.id] = block;               });               // This is a duplicate and we need to throw an error -             throw new Error('Duplicates in a repeater are not allowed. Repeater: ' + expression + -                 ' key: ' + trackById); +             throw ngError(50, "ngRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}", +                                                                                                                                                    expression,       trackById);             } else {               // new never before seen block               nextBlockOrder[index] = { id: trackById }; diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js index 7a1cab53..6dda33f5 100644 --- a/src/ng/directive/select.js +++ b/src/ng/directive/select.js @@ -300,9 +300,9 @@ var selectDirective = ['$compile', '$parse', function($compile,   $parse) {          var match;          if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) { -          throw Error( -            "Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_ (track by _expr_)?'" + -            " but got '" + optionsExp + "'."); +          throw ngError(9, +            "ngOptions error! Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}", +            optionsExp, startingTag(selectElement));          }          var displayFn = $parse(match[2] || match[1]), @@ -357,7 +357,7 @@ var selectDirective = ['$compile', '$parse', function($compile,   $parse) {                        for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {                          locals[valueName] = collection[trackIndex];                          if (trackFn(scope, locals) == key) break; -                      }  +                      }                      } else {                        locals[valueName] = collection[key];                      } diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index ed8404f9..5b965705 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -2,7 +2,7 @@ var XHR = window.XMLHttpRequest || function() {    try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}    try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}    try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {} -  throw new Error("This browser does not support XMLHttpRequest."); +  throw ngError(19, "This browser does not support XMLHttpRequest.");  }; diff --git a/src/ng/interpolate.js b/src/ng/interpolate.js index dcf05d77..42218fd3 100644 --- a/src/ng/interpolate.js +++ b/src/ng/interpolate.js @@ -139,7 +139,7 @@ function $InterpolateProvider() {              return concat.join('');            }            catch(err) { -            var newErr = new Error('Error while interpolating: ' + text + '\n' + err.toString()); +            var newErr = ngError(48, "$interpolate error! Can't interpolate: {0}\n{1}", text, err.toString());              $exceptionHandler(newErr);            }          }; diff --git a/src/ng/location.js b/src/ng/location.js index 4efa019c..7b011abe 100644 --- a/src/ng/location.js +++ b/src/ng/location.js @@ -95,7 +95,7 @@ function LocationHtml5Url(appBase, basePrefix) {      matchUrl(url, parsed);      var pathUrl = beginsWith(appBaseNoFile, url);      if (!isString(pathUrl)) { -      throw Error('Invalid url "' + url + '", missing path prefix "' + appBaseNoFile + '".'); +      throw ngError(21, '$location error! Invalid url "{0}", missing path prefix "{1}".', url, appBaseNoFile);      }      matchAppUrl(pathUrl, parsed);      extend(this, parsed); @@ -157,11 +157,11 @@ function LocationHashbangUrl(appBase, hashPrefix) {      matchUrl(url, this);      var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);      if (!isString(withoutBaseUrl)) { -      throw new Error('Invalid url "' + url + '", does not start with "' + appBase +  '".'); +      throw ngError(22, '$location error! Invalid url "{0}", does not start with "{1}".', url, appBase);      }      var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' ? beginsWith(hashPrefix, withoutBaseUrl) : withoutBaseUrl;      if (!isString(withoutHashUrl)) { -      throw new Error('Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '".'); +      throw ngError(49, '$location error! Invalid url "{0}", missing hash prefix "{1}".', url, hashPrefix);      }      matchAppUrl(withoutHashUrl, this);      this.$$compose(); diff --git a/src/ng/parse.js b/src/ng/parse.js index 4616d15d..5af52f60 100644 --- a/src/ng/parse.js +++ b/src/ng/parse.js @@ -123,11 +123,11 @@ function lex(text, csp){    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 + "]."); +    var colStr = (isDefined(start) ? +        "s " + start +  "-" + index + " [" + text.substring(start, end) + "]" +        : " " + end); +    throw ngError(23, "Lexer Error: {0} at column{1} in expression [{2}].", +        error, colStr, text);    }    function readNumber() { @@ -309,15 +309,14 @@ function parser(text, json, $filter, csp){    ///////////////////////////////////    function throwError(msg, token) { -    throw Error("Syntax Error: Token '" + token.text + -      "' " + msg + " at column " + -      (token.index + 1) + " of the expression [" + -      text + "] starting at [" + text.substring(token.index) + "]."); +    throw ngError(24, +        "Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].", +        token.text, msg, (token.index + 1), text, text.substring(token.index));    }    function peekToken() {      if (tokens.length === 0) -      throw Error("Unexpected end of expression: " + text); +      throw ngError(25, "Unexpected end of expression: {0}", text);      return tokens[0];    } @@ -366,7 +365,7 @@ function parser(text, json, $filter, csp){        constant: left.constant && middle.constant && right.constant      });    } -   +    function binaryFn(left, fn, right) {      return extend(function(self, locals) {        return fn(self, locals, left, right); @@ -471,7 +470,7 @@ function parser(text, json, $filter, csp){        return left;      }    } -   +    function logicalOR() {      var left = logicalAND();      var token; diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index 904f24d4..66486551 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -161,10 +161,6 @@ function $RootScopeProvider(){          var Child,              child; -        if (isFunction(isolate)) { -          // TODO: remove at some point -          throw Error('API-CHANGE: Use $controller to instantiate controllers.'); -        }          if (isolate) {            child = new Scope();            child.$root = this.$root; @@ -560,8 +556,9 @@ function $RootScopeProvider(){            if(dirty && !(ttl--)) {              clearPhase(); -            throw Error(TTL + ' $digest() iterations reached. Aborting!\n' + -                'Watchers fired in the last 5 iterations: ' + toJson(watchLog)); +            throw ngError(27, +                '{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}', +                TTL, toJson(watchLog));            }          } while (dirty || asyncQueue.length); @@ -923,7 +920,7 @@ function $RootScopeProvider(){      function beginPhase(phase) {        if ($rootScope.$$phase) { -        throw Error($rootScope.$$phase + ' already in progress'); +        throw ngError(28, '{0} already in progress', $rootScope.$$phase);        }        $rootScope.$$phase = phase; | 
