fix($injector): refactor module loading code and use minErr

This commit is contained in:
Igor Minar 2013-07-01 17:23:24 -07:00
parent 48eb297c11
commit 4f0f243771
4 changed files with 44 additions and 35 deletions

View file

@ -494,37 +494,36 @@ function createInjector(modulesToLoad) {
forEach(modulesToLoad, function(module) { forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return; if (loadedModules.get(module)) return;
loadedModules.put(module, true); loadedModules.put(module, true);
if (isString(module)) {
var moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
try { try {
if (isString(module)) {
var moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) { for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
var invokeArgs = invokeQueue[i], var invokeArgs = invokeQueue[i],
provider = providerInjector.get(invokeArgs[0]); provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]); provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
} }
} catch (e) { } else if (isFunction(module)) {
if (e.message) e.message += ' from ' + module; runBlocks.push(providerInjector.invoke(module));
throw e; } else if (isArray(module)) {
runBlocks.push(providerInjector.invoke(module));
} else {
assertArgFn(module, 'module');
} }
} else if (isFunction(module)) { } catch (e) {
try { if (isArray(module)) {
runBlocks.push(providerInjector.invoke(module)); module = module[module.length - 1];
} catch (e) {
if (e.message) e.message += ' from ' + module;
throw e;
} }
} else if (isArray(module)) { if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
try { // Safari & FF's stack traces don't contain error.message content unlike those of Chrome and IE
runBlocks.push(providerInjector.invoke(module)); // So if stack doesn't contain message, we create a new string that contains both.
} catch (e) { // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
if (e.message) e.message += ' from ' + String(module[module.length - 1]); e = e.message + '\n' + e.stack;
throw e;
} }
} else { throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", module, e.stack || e.message || e);
assertArgFn(module, 'module');
} }
}); });
return runBlocks; return runBlocks;

View file

@ -3,7 +3,7 @@
/** /**
* @description * @description
* *
* This object provides a utility for producing rich Error messages within * This object provides a utility for producing rich Error messages within
* Angular. It can be called as follows: * Angular. It can be called as follows:
* *
* var exampleMinErr = minErr('example'); * var exampleMinErr = minErr('example');
@ -34,14 +34,14 @@ function minErr(module) {
template = arguments[1], template = arguments[1],
templateArgs = arguments, templateArgs = arguments,
message; message;
message = prefix + template.replace(/\{\d+\}/g, function (match) { message = prefix + template.replace(/\{\d+\}/g, function (match) {
var index = +match.slice(1, -1), arg; var index = +match.slice(1, -1), arg;
if (index + 2 < templateArgs.length) { if (index + 2 < templateArgs.length) {
arg = templateArgs[index + 2]; arg = templateArgs[index + 2];
if (isFunction(arg)) { if (isFunction(arg)) {
return arg.toString().replace(/ \{[\s\S]*$/, ''); return arg.toString().replace(/ ?\{[\s\S]*$/, '');
} else if (isUndefined(arg)) { } else if (isUndefined(arg)) {
return 'undefined'; return 'undefined';
} else if (!isString(arg)) { } else if (!isString(arg)) {

View file

@ -605,7 +605,9 @@ describe('angular', function() {
expect(function() { expect(function() {
angularInit(appElement, bootstrap); angularInit(appElement, bootstrap);
}).toThrow("[$injector:nomod] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it."); }).toThrowMatching(
/\[\$injector:modulerr] Failed to instantiate module doesntexist due to:\n.*\[\$injector:nomod] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it\./
);
}); });
}); });
@ -749,7 +751,8 @@ describe('angular', function() {
expect(function() { expect(function() {
angular.bootstrap(element, ['doesntexist']); angular.bootstrap(element, ['doesntexist']);
}).toThrow("[$injector:nomod] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it."); }).toThrowMatching(
/\[\$injector:modulerr\] Failed to instantiate module doesntexist due to:\n.*\[\$injector:nomod\] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it\./);
expect(element.html()).toBe('{{1+2}}'); expect(element.html()).toBe('{{1+2}}');
dealoc(element); dealoc(element);

View file

@ -268,8 +268,9 @@ describe('injector', function() {
it('should error on invalid module name', function() { it('should error on invalid module name', function() {
expect(function() { expect(function() {
createInjector(['IDontExist'], {}); createInjector(['IDontExist'], {});
}).toThrow("[$injector:nomod] Module 'IDontExist' is not available! You either misspelled the module name or forgot to load it."); }).toThrowMatching(
/\[\$injector:modulerr\].+\n.*\[\$injector:nomod] Module 'IDontExist' is not available! You either misspelled the module name or forgot to load it/
);
}); });
@ -552,7 +553,7 @@ describe('injector', function() {
createInjector([ createInjector([
{} {}
], {}); ], {});
}).toThrow("[ng:areq] Argument 'module' is not a function, got Object"); }).toThrowMatching(/\[\$injector:modulerr\] Failed to instantiate module {} due to:\n.*\[ng\:areq] Argument 'module' is not a function, got Object/);
}); });
@ -561,15 +562,17 @@ describe('injector', function() {
createInjector([function() { createInjector([function() {
throw 'MyError'; throw 'MyError';
}], {}); }], {});
}).toThrow('MyError'); }).toThrowMatching(/\[\$injector:modulerr\] Failed to instantiate module .+ due to:\n.*MyError/);
}); });
it('should decorate the missing service error with module name', function() { it('should decorate the missing service error with module name', function() {
angular.module('TestModule', [], function(xyzzy) {}); angular.module('TestModule', [], function(xyzzy) {});
expect(function() { expect(function() {
createInjector(['TestModule']); createInjector(['TestModule' ]);
}).toThrow('[$injector:unpr] Unknown provider: xyzzy from TestModule'); }).toThrowMatching(
/\[\$injector:modulerr\] Failed to instantiate module TestModule due to:\n.*\[\$injector:unpr] Unknown provider: xyzzy/
);
}); });
@ -577,7 +580,9 @@ describe('injector', function() {
function myModule(xyzzy){} function myModule(xyzzy){}
expect(function() { expect(function() {
createInjector([myModule]); createInjector([myModule]);
}).toThrow('[$injector:unpr] Unknown provider: xyzzy from ' + myModule); }).toThrowMatching(
/\[\$injector:modulerr\] Failed to instantiate module function myModule\(xyzzy\) due to:\n.*\[\$injector:unpr] Unknown provider: xyzzy/
);
}); });
@ -585,7 +590,9 @@ describe('injector', function() {
function myModule(xyzzy){} function myModule(xyzzy){}
expect(function() { expect(function() {
createInjector([['xyzzy', myModule]]); createInjector([['xyzzy', myModule]]);
}).toThrow('[$injector:unpr] Unknown provider: xyzzy from ' + myModule); }).toThrowMatching(
/\[\$injector:modulerr\] Failed to instantiate module function myModule\(xyzzy\) due to:\n.*\[\$injector:unpr] Unknown provider: xyzzy/
);
}); });
@ -801,7 +808,7 @@ describe('injector', function() {
createInjector([function($provide) { createInjector([function($provide) {
$provide.value('name', 'angular') $provide.value('name', 'angular')
}, instanceLookupInModule]); }, instanceLookupInModule]);
}).toThrow('[$injector:unpr] Unknown provider: name from ' + String(instanceLookupInModule)); }).toThrowMatching(/\[\$injector:unpr] Unknown provider: name/);
}); });
}); });
}); });