diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Angular.js | 7 | ||||
| -rw-r--r-- | src/auto/injector.js | 9 | ||||
| -rw-r--r-- | src/jqLite.js | 2 | ||||
| -rw-r--r-- | src/loader.js | 2 | ||||
| -rw-r--r-- | src/minErr.js | 57 | ||||
| -rw-r--r-- | src/ng/cacheFactory.js | 2 | ||||
| -rw-r--r-- | src/ng/compile.js | 17 | ||||
| -rw-r--r-- | src/ng/controller.js | 2 | ||||
| -rw-r--r-- | src/ng/directive/input.js | 9 | ||||
| -rw-r--r-- | src/ng/directive/ngRepeat.js | 7 | ||||
| -rw-r--r-- | src/ng/directive/select.js | 4 | ||||
| -rw-r--r-- | src/ng/httpBackend.js | 2 | ||||
| -rw-r--r-- | src/ng/interpolate.js | 2 | ||||
| -rw-r--r-- | src/ng/location.js | 7 | ||||
| -rw-r--r-- | src/ng/parse.js | 7 | ||||
| -rw-r--r-- | src/ng/rootScope.js | 5 | ||||
| -rw-r--r-- | src/ngError.js | 47 |
17 files changed, 103 insertions, 85 deletions
diff --git a/src/Angular.js b/src/Angular.js index c9b6d530..2fb8f66c 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -54,6 +54,7 @@ var /** holds major version number for IE or NaN for real browsers */ slice = [].slice, push = [].push, toString = Object.prototype.toString, + ngMinErr = minErr('ng'), _angular = window.angular, @@ -573,7 +574,7 @@ function isLeafNode (node) { */ function copy(source, destination){ if (isWindow(source) || isScope(source)) { - throw ngError(43, "Can't copy! Making copies of Window or Scope instances is not supported."); + throw ngMinErr('cpws', "Can't copy! Making copies of Window or Scope instances is not supported."); } if (!destination) { @@ -588,7 +589,7 @@ function copy(source, destination){ } } } else { - if (source === destination) throw ngError(44, "Can't copy! Source and destination are identical."); + if (source === destination) throw ngMinErr('cpi', "Can't copy! Source and destination are identical."); if (isArray(source)) { destination.length = 0; for ( var i = 0; i < source.length; i++) { @@ -1044,7 +1045,7 @@ function bindJQuery() { */ function assertArg(arg, name, reason) { if (!arg) { - throw ngError(45, "Argument '{0}' is {1}", (name || '?'), (reason || "required")); + throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); } return arg; } diff --git a/src/auto/injector.js b/src/auto/injector.js index 1bd56acd..e43f2df7 100644 --- a/src/auto/injector.js +++ b/src/auto/injector.js @@ -42,6 +42,7 @@ var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; +var $injectorMinErr = minErr('$injector'); function annotate(fn) { var $inject, fnText, @@ -422,7 +423,7 @@ function createInjector(modulesToLoad) { }, providerInjector = (providerCache.$injector = createInternalInjector(providerCache, function() { - throw ngError(1, "Unknown provider: {0}", path.join(' <- ')); + throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); })), instanceCache = {}, instanceInjector = (instanceCache.$injector = @@ -455,7 +456,7 @@ function createInjector(modulesToLoad) { provider_ = providerInjector.instantiate(provider_); } if (!provider_.$get) { - throw ngError(2, "Provider '{0}' must define $get factory method.", name); + throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); } return providerCache[name + providerSuffix] = provider_; } @@ -538,7 +539,7 @@ function createInjector(modulesToLoad) { function getService(serviceName) { if (cache.hasOwnProperty(serviceName)) { if (cache[serviceName] === INSTANTIATING) { - throw ngError(4, 'Circular dependency found: {0}', path.join(' <- ')); + throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- ')); } return cache[serviceName]; } else { @@ -561,7 +562,7 @@ function createInjector(modulesToLoad) { for(i = 0, length = $inject.length; i < length; i++) { key = $inject[i]; if (typeof key !== 'string') { - throw ngError(3, 'Incorrect injection token! Expected service name as string, got {0}', key); + throw $injectorMinErr('itkn', 'Incorrect injection token! Expected service name as string, got {0}', key); } args.push( locals && locals.hasOwnProperty(key) diff --git a/src/jqLite.js b/src/jqLite.js index 4c68cdef..dc1f03e8 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -153,7 +153,7 @@ function JQLite(element) { } if (!(this instanceof JQLite)) { if (isString(element) && element.charAt(0) != '<') { - throw ngError(46, 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element'); + throw minErr('jqLite')('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element'); } return new JQLite(element); } diff --git a/src/loader.js b/src/loader.js index 7c96a20d..a40a305d 100644 --- a/src/loader.js +++ b/src/loader.js @@ -70,7 +70,7 @@ function setupModuleLoader(window) { } return ensure(modules, name, function() { if (!requires) { - throw ngError(47, "Module '{0}' is not available! You either misspelled the module name or forgot to load it.", name); + throw minErr('$injector')('nomod', "Module '{0}' is not available! You either misspelled the module name or forgot to load it.", name); } /** @type {!Array.<Array.<*>>} */ diff --git a/src/minErr.js b/src/minErr.js new file mode 100644 index 00000000..b6c447ca --- /dev/null +++ b/src/minErr.js @@ -0,0 +1,57 @@ +'use strict'; + +/** + * @description + * + * This object provides a utility for producing rich Error messages within + * Angular. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace') . Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @returns {function(string, string, ...): Error} instance + */ + +function minErr(module) { + return function () { + var prefix = '[' + (module ? module + ':' : '') + arguments[0] + '] ', + template = arguments[1], + templateArgs = arguments, + message; + + message = prefix + template.replace(/\{\d+\}/g, function (match) { + var index = +match.slice(1, -1), arg; + + if (index + 2 < templateArgs.length) { + arg = templateArgs[index + 2]; + if (isFunction(arg)) { + return arg.toString().replace(/ \{[\s\S]*$/, ''); + } else if (isUndefined(arg)) { + return 'undefined'; + } else if (!isString(arg)) { + return toJson(arg); + } + return arg; + } + return match; + }); + + return new Error(message); + }; +} diff --git a/src/ng/cacheFactory.js b/src/ng/cacheFactory.js index 1c23e063..7fcf81ff 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 ngError(10, "CacheId '{0}' is already taken!", cacheId); + throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId); } var size = 0, diff --git a/src/ng/compile.js b/src/ng/compile.js index ba6e6306..faef4772 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -138,6 +138,7 @@ * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. */ +var $compileMinErr = minErr('$compile'); /** * @ngdoc service @@ -589,7 +590,7 @@ function $CompileProvider($provide) { var startNode = node; do { if (!node) { - throw ngError(51, "Unterminated attribute, found '{0}' but no matching '{1}' found.", attrStart, attrEnd); + throw $compileMinErr('utrat', "Unterminated attribute, found '{0}' but no matching '{1}' found.", attrStart, attrEnd); } if (node.nodeType == 1 /** Element **/) { if (node.hasAttribute(attrStart)) depth++; @@ -721,7 +722,7 @@ function $CompileProvider($provide) { compileNode = $template[0]; if ($template.length != 1 || compileNode.nodeType !== 1) { - throw ngError(12, "Template for directive '{0}' must have exactly one root element.", directiveName); + throw $compileMinErr('tplrt', "Template for directive '{0}' must have exactly one root element. {1}", directiveName, ''); } replaceWith(jqCollection, $compileNode, compileNode); @@ -809,7 +810,7 @@ function $CompileProvider($provide) { } value = $element[retrievalMethod]('$' + require + 'Controller'); if (!value && !optional) { - throw ngError(13, "Controller '{0}', required by directive '{1}', can't be found!", require, directiveName); + throw $compileMinErr('ctreq', "Controller '{0}', required by directive '{1}', can't be found!", require, directiveName); } return value; } else if (isArray(require)) { @@ -869,7 +870,7 @@ 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 ngError(14, "Expression '{0}' used with directive '{1}' is non-assignable!", + throw $compileMinErr('noass', "Expression '{0}' used with directive '{1}' is non-assignable!", attrs[attrName], newIsolateScopeDirective.name); }; lastValue = scope[scopeName] = parentGet(parentScope); @@ -900,7 +901,7 @@ function $CompileProvider($provide) { } default: { - throw ngError(15, "Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}", + throw $compileMinErr('iscp', "Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}", newIsolateScopeDirective.name, scopeName, definition); } } @@ -1057,7 +1058,7 @@ function $CompileProvider($provide) { compileNode = $template[0]; if ($template.length != 1 || compileNode.nodeType !== 1) { - throw ngError(16, "Template for directive '{0}' must have exactly one root element. Template: {1}", + throw $compileMinErr('tplrt', "Template for directive '{0}' must have exactly one root element. {1}", origAsyncDirective.name, templateUrl); } @@ -1095,7 +1096,7 @@ function $CompileProvider($provide) { linkQueue = null; }). error(function(response, code, headers, config) { - throw ngError(17, 'Failed to load template: {0}', config.url); + throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url); }); return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) { @@ -1123,7 +1124,7 @@ function $CompileProvider($provide) { function assertNoDuplicate(what, previousDirective, directive, element) { if (previousDirective) { - throw ngError(18, 'Multiple directives [{0}, {1}] asking for {2} on: {3}', + throw $compileMinErr('multidir', '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 2df0bde9..2078eef8 100644 --- a/src/ng/controller.js +++ b/src/ng/controller.js @@ -75,7 +75,7 @@ function $ControllerProvider() { if (identifier) { 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); + throw minErr('$controller')('noscp', "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 591da99e..31a3ba5d 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -475,8 +475,9 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { var patternObj = scope.$eval(pattern); if (!patternObj || !patternObj.test) { - throw ngError(5, 'ngPattern error! Expected {0} to be a RegExp but was {1}. Element: {2}', - pattern, patternObj, startingTag(element)); + throw minErr('ngPattern')('noregexp', + 'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern, + patternObj, startingTag(element)); } return validate(patternObj, value); }; @@ -928,8 +929,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ ngModelSet = ngModelGet.assign; if (!ngModelSet) { - throw ngError(6, "ngModel error! Expression '{0}' is non-assignable. Element: {1}", $attr.ngModel, - startingTag($element)); + throw minErr('ngModel')('noass', "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 53ab4fdc..c0e2292f 100644 --- a/src/ng/directive/ngRepeat.js +++ b/src/ng/directive/ngRepeat.js @@ -191,6 +191,7 @@ */ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) { var NG_REMOVED = '$$NG_REMOVED'; + var ngRepeatMinErr = minErr('ngRepeat'); return { transclude: 'element', priority: 1000, @@ -204,7 +205,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) { hashFnLocals = {$id: hashKey}; if (!match) { - throw ngError(7, "ngRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", + throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", expression); } @@ -229,7 +230,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) { match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/); if (!match) { - throw ngError(8, "ngRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.", + throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.", lhs); } valueIdentifier = match[3] || match[1]; @@ -291,7 +292,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) { if (block && block.startNode) lastBlockMap[block.id] = block; }); // This is a duplicate and we need to throw an error - 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}", + throw ngRepeatMinErr('dupes', "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 diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js index b7a4f58b..0d5221fb 100644 --- a/src/ng/directive/select.js +++ b/src/ng/directive/select.js @@ -300,8 +300,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { var match; if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) { - throw ngError(9, - "ngOptions error! Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}", + throw minErr('ngOptions')('iexp', + "Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}", optionsExp, startingTag(selectElement)); } diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 5b965705..69711df2 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 ngError(19, "This browser does not support XMLHttpRequest."); + throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest."); }; diff --git a/src/ng/interpolate.js b/src/ng/interpolate.js index 42218fd3..51f4630d 100644 --- a/src/ng/interpolate.js +++ b/src/ng/interpolate.js @@ -139,7 +139,7 @@ function $InterpolateProvider() { return concat.join(''); } catch(err) { - var newErr = ngError(48, "$interpolate error! Can't interpolate: {0}\n{1}", text, err.toString()); + var newErr = minErr('$interpolate')('interr', "Can't interpolate: {0}\n{1}", text, err.toString()); $exceptionHandler(newErr); } }; diff --git a/src/ng/location.js b/src/ng/location.js index 7b011abe..de629d42 100644 --- a/src/ng/location.js +++ b/src/ng/location.js @@ -3,6 +3,7 @@ var SERVER_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/, DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; +var $locationMinErr = minErr('$location'); /** @@ -95,7 +96,7 @@ function LocationHtml5Url(appBase, basePrefix) { matchUrl(url, parsed); var pathUrl = beginsWith(appBaseNoFile, url); if (!isString(pathUrl)) { - throw ngError(21, '$location error! Invalid url "{0}", missing path prefix "{1}".', url, appBaseNoFile); + throw $locationMinErr('nopp', 'Invalid url "{0}", missing path prefix "{1}".', url, appBaseNoFile); } matchAppUrl(pathUrl, parsed); extend(this, parsed); @@ -157,11 +158,11 @@ function LocationHashbangUrl(appBase, hashPrefix) { matchUrl(url, this); var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url); if (!isString(withoutBaseUrl)) { - throw ngError(22, '$location error! Invalid url "{0}", does not start with "{1}".', url, appBase); + throw $locationMinErr('istart', 'Invalid url "{0}", does not start with "{1}".', url, appBase); } var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' ? beginsWith(hashPrefix, withoutBaseUrl) : withoutBaseUrl; if (!isString(withoutHashUrl)) { - throw ngError(49, '$location error! Invalid url "{0}", missing hash prefix "{1}".', url, hashPrefix); + throw $locationMinErr('nohash', '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 5af52f60..8bb4b5e9 100644 --- a/src/ng/parse.js +++ b/src/ng/parse.js @@ -36,6 +36,7 @@ var OPERATORS = { '!':function(self, locals, a){return !a(self, locals);} }; var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'}; +var $parseMinErr = minErr('$parse'); function lex(text, csp){ var tokens = [], @@ -126,7 +127,7 @@ function lex(text, csp){ var colStr = (isDefined(start) ? "s " + start + "-" + index + " [" + text.substring(start, end) + "]" : " " + end); - throw ngError(23, "Lexer Error: {0} at column{1} in expression [{2}].", + throw $parseMinErr('lexerr', "Lexer Error: {0} at column{1} in expression [{2}].", error, colStr, text); } @@ -309,14 +310,14 @@ function parser(text, json, $filter, csp){ /////////////////////////////////// function throwError(msg, token) { - throw ngError(24, + throw $parseMinErr('syntax', "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 ngError(25, "Unexpected end of expression: {0}", text); + throw $parseMinErr('ueoe', "Unexpected end of expression: {0}", text); return tokens[0]; } diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index 66486551..4db38804 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -60,6 +60,7 @@ */ function $RootScopeProvider(){ var TTL = 10; + var $rootScopeMinErr = minErr('$rootScope'); this.digestTtl = function(value) { if (arguments.length) { @@ -556,7 +557,7 @@ function $RootScopeProvider(){ if(dirty && !(ttl--)) { clearPhase(); - throw ngError(27, + throw $rootScopeMinErr('infdig', '{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}', TTL, toJson(watchLog)); } @@ -920,7 +921,7 @@ function $RootScopeProvider(){ function beginPhase(phase) { if ($rootScope.$$phase) { - throw ngError(28, '{0} already in progress', $rootScope.$$phase); + throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase); } $rootScope.$$phase = phase; diff --git a/src/ngError.js b/src/ngError.js deleted file mode 100644 index d054336c..00000000 --- a/src/ngError.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -/** - * @description - * - * This object extends the error class and provides interpolation capability - * to make it easier to write and read Error messages within Angular. It can - * be called as follows: - * - * throw ngError(13, 'This {0} is {1}', foo, bar); - * - * The above will replace {0} with the value of foo, and {1} with the value of - * bar. The object is not restricted in the number of arguments it can take. - * - * If fewer arguments are specified than necessary for interpolation, the extra - * interpolation markers will be preserved in the final string. - * - * @param {...} arguments The first argument to this object is the error - * number, the second argument the message with templated points for - * Interpolation (of the for {0} for the first, {1} for the second and - * so on). The second argument onwards are interpolated into the error - * message string in order. - */ -function ngError() { - var message = '[NgErr' + arguments[0] + '] ' + arguments[1], - i = 0, - l = arguments.length - 2, - curlyRegexp, arg; - - for (; i < l; i++) { - curlyRegexp = new RegExp("\\{" + i + "\\}", "gm"); - arg = arguments[i + 2]; - - if (isFunction(arg)) { - arg = arg.toString().replace(/ \{[\s\S]*$/, ''); - } else if (!isString(arg)) { - arg = toJson(arg); - } - - message = message.replace(curlyRegexp, arg); - } - - // even if we are called as constructor we can bypass the new ngError instance and return - // an instance of a real Error that contains correct stack info + extra frame for ngError call - // TODO(i): can we rewrite the stack string to remove ngError frame? - return new Error(message); -} |
